Skip to main content

caixa_core/
manifest.rs

1use std::path::{Path, PathBuf};
2
3use serde::{Deserialize, Serialize};
4use tatara_lisp::DeriveTataraDomain;
5
6use thiserror::Error;
7
8use crate::{
9    CaixaKind, Dep,
10    behavior::BehaviorSpec,
11    dep::DepError,
12    limits::LimitsSpec,
13    render::{
14        PathShapeViolation, is_computeunit_yaml_extension, is_git_repo_url, is_lisp_extension,
15        is_sandboxed_relative_path,
16    },
17    supervisor::SupervisorSpec,
18    upgrade::UpgradeFromEntry,
19};
20
21/// Top-level manifest for a caixa (a tatara-lisp package).
22///
23/// Authored as `caixa.lisp`:
24///
25/// ```lisp
26/// (defcaixa
27///   :nome        "pangea-tatara-aws"
28///   :versao      "0.1.0"
29///   :kind        Biblioteca
30///   :edicao      "2026"
31///   :descricao   "AWS provider caixa for tatara-lisp"
32///   :repositorio "github:pleme-io/pangea-tatara-aws"
33///   :licenca     "MIT"
34///   :autores     ("pleme-io")
35///   :etiquetas   ("iac" "aws" "pangea")
36///   :deps        ((:nome "caixa-teia"    :versao "^0.1")
37///                 (:nome "iac-forge-ir"  :versao "^0.5"))
38///   :deps-dev    ((:nome "tatara-check"  :versao "*"))
39///   :bibliotecas ("lib/pangea-tatara-aws.lisp"))
40/// ```
41///
42/// Because `Caixa` derives [`tatara_lisp::domain::TataraDomain`], the manifest
43/// is parsed directly by the tatara-lisp compiler — an ill-formed manifest is
44/// a compile error, not a runtime error.
45#[derive(DeriveTataraDomain, Serialize, Deserialize, Debug, Clone, PartialEq)]
46#[serde(rename_all = "camelCase")]
47#[tatara(keyword = "defcaixa")]
48pub struct Caixa {
49    /// Package name — the canonical string used in `:deps`, the registry, and
50    /// the default lib/exe entry names.
51    pub nome: String,
52
53    /// Package version — a semver literal like `"0.1.0"`. Parsed lazily via
54    /// [`crate::CaixaVersion::parse`].
55    pub versao: String,
56
57    /// What this caixa produces. See [`CaixaKind`].
58    pub kind: CaixaKind,
59
60    /// Language edition — determines macro surface + compatibility flags.
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub edicao: Option<String>,
63
64    /// Free-form description shown in the registry listing.
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub descricao: Option<String>,
67
68    /// Homepage or repo URL.
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub repositorio: Option<String>,
71
72    /// SPDX license expression — `"MIT"`, `"Apache-2.0 OR MIT"`, etc.
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub licenca: Option<String>,
75
76    /// Authors — free-form strings.
77    #[serde(default)]
78    pub autores: Vec<String>,
79
80    /// Topical tags used for registry search.
81    #[serde(default)]
82    pub etiquetas: Vec<String>,
83
84    /// Runtime dependencies.
85    #[serde(default)]
86    pub deps: Vec<Dep>,
87
88    /// Development-only dependencies (tests, lint, bench).
89    #[serde(default)]
90    pub deps_dev: Vec<Dep>,
91
92    /// Paths to executable entry points (relative to the package root).
93    /// Required when `:kind Binario`.
94    #[serde(default)]
95    pub exe: Vec<String>,
96
97    /// Paths to library entry points (relative to the package root).
98    /// First entry is the canonical `lib/<nome>.lisp`; when omitted under
99    /// `:kind Biblioteca`, the layout check expects `lib/<nome>.lisp`.
100    #[serde(default)]
101    pub bibliotecas: Vec<String>,
102
103    /// Paths to service manifests (relative to the package root).
104    /// Required when `:kind Servico`.
105    #[serde(default)]
106    pub servicos: Vec<String>,
107
108    // ── M2 typed-substrate extensions per theory/ABSORPTION-ROADMAP.md ──
109    //
110    // All four are optional + default to "absent"; existing caixas
111    // round-trip unchanged. Each maps onto a prior-art primitive named
112    // in theory/INSPIRATIONS.md:
113    //
114    //   :limits        — Lunatic per-process limits (§III.1)
115    //   :behavior      — OTP gen_server callbacks  (§II.3)
116    //   :upgrade-from  — OTP appup migration       (§II.4)
117    //   :estrategia    — OTP supervisor strategy   (§II.2 + §III.2)
118    //   :children      — OTP supervisor children    (§II.2 + §III.2)
119    //
120    // The supervisor slots are flat on Caixa (vs nested under a
121    // SupervisorSpec sub-form) to keep tatara-lisp authoring at one
122    // level of nesting; SupervisorSpec exists for validation +
123    // composition convenience (`Caixa::supervisor_view()`).
124    /// Lunatic-style per-process resource limits. None = unbounded.
125    #[serde(default, skip_serializing_if = "Option::is_none")]
126    pub limits: Option<LimitsSpec>,
127
128    /// OTP-shaped behavior callbacks for Servico-kind caixas.
129    /// Authored as `(:on-init "..." :on-call "..." …)`.
130    #[serde(default, skip_serializing_if = "Option::is_none")]
131    pub behavior: Option<BehaviorSpec>,
132
133    /// OTP appup — declarative upgrade instructions per prior version.
134    /// Empty list = no hot-upgrade path declared (caller falls back to
135    /// `:Restart` strategy).
136    #[serde(default)]
137    pub upgrade_from: Vec<UpgradeFromEntry>,
138
139    /// OTP supervisor strategy. Required when `:kind Supervisor`;
140    /// ignored otherwise.
141    #[serde(default, skip_serializing_if = "Option::is_none")]
142    pub estrategia: Option<crate::supervisor::RestartStrategy>,
143
144    /// Max restarts before the supervisor itself fails. Defaults via
145    /// SupervisorSpec at validation time.
146    #[serde(default, skip_serializing_if = "Option::is_none")]
147    pub max_restarts: Option<u32>,
148
149    /// Sliding window for `max_restarts`. Authored as a duration
150    /// string (`"60s"`, `"5m"`).
151    #[serde(default, skip_serializing_if = "Option::is_none")]
152    pub restart_window: Option<String>,
153
154    /// Static children of a supervisor. Required for OneForOne /
155    /// OneForAll / RestForOne; must be empty for SimpleOneForOne.
156    #[serde(default)]
157    pub children: Vec<crate::supervisor::ChildSpec>,
158
159    // ── M3 Aplicacao slots (theory/MESH-COMPOSITION.md) ─────────────────
160    //
161    // Required when :kind Aplicacao; ignored otherwise.
162    // Composed into a typed AplicacaoSpec via Caixa::aplicacao_view().
163    /// Member Servicos that make up this Aplicacao. Each is a
164    /// caixa-name + version-constraint pair. Required for Aplicacao.
165    #[serde(default)]
166    pub membros: Vec<crate::aplicacao::Membro>,
167
168    /// WIT-typed inter-Servico contracts. Each `:de` and `:para`
169    /// must reference a name in `:membros`.
170    #[serde(default)]
171    pub contratos: Vec<crate::aplicacao::WitContract>,
172
173    /// Mesh-level policies (timeout, retries, circuit-breaker, mTLS,
174    /// rate-limit). Apply to every contrato unless overridden per-edge
175    /// in M4.
176    #[serde(default, skip_serializing_if = "Option::is_none")]
177    pub politicas: Option<crate::aplicacao::MeshPolicy>,
178
179    /// Placement strategy across the cluster fleet
180    /// (single-node | replicated | sharded).
181    #[serde(default, skip_serializing_if = "Option::is_none")]
182    pub placement: Option<crate::aplicacao::Placement>,
183
184    /// External entry point — gateway / ingress shape. Optional;
185    /// only for public Aplicacaos.
186    #[serde(default, skip_serializing_if = "Option::is_none")]
187    pub entrada: Option<crate::aplicacao::Entrada>,
188
189    // ── Acao slot (CANTEIRO §7.1-C) ──────────────────────────────────────
190    //
191    // Required when :kind Acao; ignored otherwise (mirrors the M2/
192    // supervisor-tree/M3 slot triads above — a declared-but-foreign `:ci`
193    // is a `LayoutError::CiOnNonAcao` build error, not a silent drop).
194    /// Typed CI run — a repo's CI run as a set of typed nodes + their
195    /// dependency edges. Required for `:kind Acao`; validated (not
196    /// rendered) by the `caixa-actions` renderer via
197    /// `canteiro_types::decompose`. See `caixa-actions`' crate docs for
198    /// the M0 validate-only contract.
199    #[serde(default, skip_serializing_if = "Option::is_none")]
200    pub ci: Option<canteiro_types::CiRun>,
201}
202
203/// Why reading a manifest into a [`Caixa`] failed.
204///
205/// Split from [`ManifestError`] (which reports a *parsed* manifest that is
206/// semantically wrong) because the two answer different questions, and the
207/// distinction is the whole point of this type: `ManifestError` means "your
208/// caixa is wrong", `LeituraError::DialetoEstrangeiro` means "this file is not
209/// a caixa".
210#[derive(Debug, thiserror::Error)]
211pub enum LeituraError {
212    /// The source is not readable as a `(defcaixa …)` package manifest — bad
213    /// syntax, a wrong head symbol, an unknown or mistyped slot.
214    ///
215    /// `#[source]`, not `#[error(transparent)]`. Transparent delegates
216    /// `source()` past the inner error to ITS source, which drops the
217    /// `LispError` off the cause chain — and `feira`'s
218    /// `load_caixa_parse_error_preserves_underlying_lisp_error_on_chain`
219    /// pins that a caller can `downcast_ref::<tatara_lisp::LispError>()`
220    /// through an anyhow context to read the typed payload. That pin caught
221    /// this exact regression when the variant first landed transparent.
222    #[error("{0}")]
223    Leitura(
224        #[source]
225        #[from]
226        tatara_lisp::LispError,
227    ),
228
229    /// The source IS a well-formed `(defcaixa …)` form, but of a different
230    /// declaration than this crate's.
231    ///
232    /// The variant that did not exist before, and whose absence is the defect.
233    /// A `(defcaixa :name "x" :ecosystem :go …)` used to reach the derive's
234    /// `parse_kwargs_strict` and come back as an unknown-keyword rejection —
235    /// byte-identical in shape to a typo in a real manifest. Measured over the
236    /// org checkout on 2026-07-31, that shape is the MAJORITY of the corpus, so
237    /// the confusing error was also the common one.
238    ///
239    /// Carrying the dialect means a consumer can branch on "not mine" without
240    /// re-parsing, and a census can count it. Every user-facing byte-string
241    /// (canonical keyword, one-line description, consuming crate) is a
242    /// projection of [`crate::dialeto::CaixaDialeto`] — the variant stores the
243    /// typed dialect and the `#[error]` template calls
244    /// [`CaixaDialeto::palavra_canonica`] /
245    /// [`CaixaDialeto::descricao`] / [`CaixaDialeto::consumidor`] on it, so
246    /// the three axes cannot silently diverge from the classification. Prior
247    /// to this closure the variant carried each accessor's return value as a
248    /// stored `&'static str` snapshot alongside `dialeto`, and the sole
249    /// constructor at [`Caixa::from_lisp`] filled all four fields — a caller
250    /// could construct `DialetoEstrangeiro { dialeto: Molde,
251    /// palavra_canonica: "defcaixa", … }` and every downstream consumer
252    /// (Display, ad-hoc audit, future JSON serialization) would silently
253    /// disagree with `dialeto.palavra_canonica() == "defmolde"`. The typed
254    /// enum owns the projections; the variant only carries the axis.
255    #[error(
256        "this is a `{palavra}` declaration ({desc}), read by \
257         {cons} — not a caixa-core package manifest. `defcaixa` is the \
258         tatara-lisp package manifest (`:nome :versao :kind :deps …`); the two \
259         are different declarations that shared one keyword until 2026-07-31",
260        palavra = dialeto.palavra_canonica(),
261        desc = dialeto.descricao(),
262        cons = dialeto.consumidor()
263    )]
264    DialetoEstrangeiro {
265        /// Which declaration this actually is. Sole authoritative axis;
266        /// every user-facing projection routes through
267        /// [`crate::dialeto::CaixaDialeto`]'s typed accessors so the four
268        /// axes cannot silently disagree.
269        dialeto: crate::dialeto::CaixaDialeto,
270    },
271
272    /// Not a manifest declaration at all.
273    #[error(transparent)]
274    Dialeto(#[from] crate::dialeto::DialetoError),
275}
276
277impl LeituraError {
278    /// Construct a [`LeituraError::DialetoEstrangeiro`] naming the
279    /// foreign-dialect classification the [`Caixa::from_lisp`] gate
280    /// refused a `(defcaixa …)` source as.
281    ///
282    /// Substrate primitive every foreign-dialect emission on the
283    /// [`Caixa::from_lisp`] classification-gate surface routes through,
284    /// folding the pre-lift uniform three-line
285    /// `Self::DialetoEstrangeiro { dialeto }` one-field struct-literal
286    /// onto one substrate primitive matching the peer
287    /// [`crate::dialeto::DialetoError::cabeca_errada`] (38d5159)
288    /// single-slot inherent-ctor discipline on the sibling
289    /// [`crate::dialeto::DialetoError`] envelope's `{ encontrado: String }`
290    /// axis, and matching the peer `LimitsError::unknown_byte_unit` /
291    /// `LimitsError::unknown_duration_unit` (`limits_codec_unit_only_ctors!`
292    /// — 29fac09) / `ManifestError::code_path_empty` (94dabc8) /
293    /// `BehaviorError::empty_path` (0e33b37) /
294    /// `UpgradeError::duplicate_from` (7e52aec) /
295    /// `AplicacaoError::placement_cluster_duplicate` (92b1c92) single-slot
296    /// inherent-ctor discipline every sibling `{ <field>: <T> }`
297    /// error-envelope variant on caixa-core's error surface now carries.
298    ///
299    /// The one open-coded wire-up site — [`Caixa::from_lisp`]'s
300    /// [`crate::dialeto::CaixaDialeto::is_molde_family`] branch after the
301    /// [`crate::dialeto::classify_form`] classification — opened the
302    /// uniform two-line `Self::DialetoEstrangeiro { dialeto }` block
303    /// against the codec-scoped `dialeto: CaixaDialeto` binding. Routes
304    /// through `LeituraError::dialeto_estrangeiro(dialeto)`, byte-equal
305    /// to the pre-lift struct-literal on the same [`Copy`]-bound
306    /// [`crate::dialeto::CaixaDialeto`] fixture, so any future widening
307    /// of the diagnostic shape (a stored source-file path alongside the
308    /// classified dialect, an authoring-surface caret offset into the
309    /// top-level form, a promotion of the plain `dialeto:` field into a
310    /// richer projection carrying both the typed dialect and a
311    /// `Vec<Suggestion>` neighborhood) lands at exactly one dispatch on
312    /// the substrate primitive rather than re-inlining the struct-literal
313    /// at every foreign-dialect emission on the classification gate.
314    #[must_use]
315    pub fn dialeto_estrangeiro(dialeto: crate::dialeto::CaixaDialeto) -> Self {
316        Self::DialetoEstrangeiro { dialeto }
317    }
318}
319
320/// Substrate-canonical universal-axis per-[`Caixa`] `:licenca` SPDX-shaped
321/// license-expression fallback for the `Option<String>` `:licenca` slot —
322/// the `"MIT"` SPDX identifier every [`caixa-helm`]-rendered
323/// `lareira-<nome>` Helm chart's `README.md` `## License` section folds an
324/// author-omitted (`None`) `:licenca` slot through, extracted as a typed
325/// `pub const` so every substrate-side consumer that resolves "what license
326/// scalar does an author-omitted `:licenca` degrade onto?" reaches for
327/// exactly one substrate-primitive `&'static str`.
328///
329/// The `:licenca` fallback axis has one production consumer today — the
330/// [`caixa-helm`] `build_readme` fold at `caixa-helm/src/lib.rs`'s
331/// `caixa.licenca().unwrap_or(CAIXA_LICENCA_DEFAULT)` `README.md`
332/// `## License` section body — with three sibling caixa-core sites that
333/// cite the `"MIT"` fallback in prose (this crate's [`Caixa::licenca`]
334/// accessor's docstring, [`Self::validate_licenca`]'s docstring, and the
335/// [`ManifestError::LicencaEmpty`] `#[error]` template's user-facing text)
336/// all quoting the exact byte-string a future substrate-side rebrand of the
337/// fallback (a tightening to `"Apache-2.0"` as the substrate absorbs the
338/// wasm-component-model conventions the `wasi:*` WIT worlds already carry,
339/// a per-cluster license-default overlay the M4 CR materializer resolves
340/// per-CR, a promotion to the plain `Option<String>` byte-string into a
341/// richer `SpdxExpression` enum once the SPDX-expression parser lands per
342/// [`Self::validate_licenca`]'s docstring roadmap) would silently split
343/// against — the caixa-helm renderer would emit the new byte, the
344/// docstrings would still cite the prior byte, and every author who reads
345/// the accessor docstring before authoring would file a fresh
346/// `:licenca "MIT"` verbatim rather than defer to the substrate default,
347/// with the drift surfacing at chart-README-audit time far from the
348/// substrate rebrand commit.
349///
350/// Prior to this lift the sole production emitter (`build_readme`) carried
351/// an inline `"MIT"` byte literal at
352/// `caixa-helm/src/lib.rs:1018`'s `.unwrap_or("MIT")` fallback arm — one
353/// occurrence of the same load-bearing per-`Caixa` universal-axis
354/// SPDX-shaped license-expression convention as the four sibling caixa-core
355/// docstring citations, drift-prone by construction ahead of the second
356/// occurrence the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
357/// materializer's per-Aplicacao registry-annotation synthesis (the
358/// [`Self::validate_licenca`] roadmap already names the `Chart.yaml
359/// annotations["artifacthub.io/license"]` axis every registry-facing chart
360/// carries as the second consumer) will surface.
361///
362/// The `"MIT"` value pins the canonical CAIXA-SDLC §I license scaffold
363/// every `feira init`-emitted [`Self::template`] carries verbatim
364/// (`:licenca "MIT"`) and every substrate-side renderer fixture
365/// ([`caixa-helm`]'s `sample_caixa`, [`caixa-flux`]'s renderer fixtures,
366/// [`caixa-mesh`]'s renderer fixtures) seeds by construction, matching the
367/// pleme-io repo `LICENSE` header this workspace itself ships under. The
368/// alternatives an author declares explicitly (compound SPDX expressions
369/// like `"Apache-2.0 OR MIT"`, permissive-family peers like
370/// `"Apache-2.0"` / `"BSD-3-Clause"`, license-with-exception forms like
371/// `"Apache-2.0 WITH LLVM-exception"`) express deliberate license postures
372/// an author declares explicitly, never a posture an author-omitted slot
373/// should silently assume by default.
374///
375/// Lifted as a typed `pub const` so the substrate's chosen license
376/// fallback has exactly one source of truth on the `:licenca` fallback
377/// axis, on the same substrate-primitive lift discipline the peer
378/// per-`Caixa` load-bearing-scalar constants
379/// ([`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`],
380/// [`crate::version::DEFAULT_GIT_REMOTE`],
381/// [`crate::version::DEFAULT_PLEME_GIT_ORG`]) already carry on the sibling
382/// per-`Caixa` universal-axis publish-side convention surface, and the
383/// same discipline the sibling M2 per-supervisor default set carries
384/// end-to-end ([`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`],
385/// [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`],
386/// [`crate::supervisor::SUPERVISOR_RESTART_WINDOW_DEFAULT`],
387/// [`crate::supervisor::SUPERVISOR_CHILD_RESTART_DEFAULT`]) and the M3
388/// per-`:placement` default set already carries
389/// ([`crate::aplicacao::PLACEMENT_ESTRATEGIA_DEFAULT`]) on the paired
390/// M2 / M3 typed-slot-default axes. First typed default on the outer
391/// top-level [`Caixa`] universal-axis surface to converge onto the
392/// substrate-primitive-lift discipline the M2 / M3 typed-slot families
393/// already carry.
394pub const CAIXA_LICENCA_DEFAULT: &str = "MIT";
395
396impl Caixa {
397    /// Parse a `caixa.lisp` source string to a typed `Caixa`.
398    ///
399    /// Classifies the dialect **before** parsing. A `(defcaixa …)` of another
400    /// declaration is [`LeituraError::DialetoEstrangeiro`], naming what it is
401    /// and who reads it, instead of an unknown-keyword rejection that reads as
402    /// "your manifest is broken".
403    ///
404    /// The ordering is load-bearing. Handing a foreign dialect to the derive
405    /// first and interpreting the failure afterwards would mean guessing from
406    /// an error message, and the guess would be wrong for every file whose
407    /// first unknown slot happens to be one both schemas could plausibly carry.
408    pub fn from_lisp(src: &str) -> Result<Self, LeituraError> {
409        use tatara_lisp::domain::TataraDomain;
410        let forms = tatara_lisp::read(src).map_err(LeituraError::Leitura)?;
411        let first = forms.first().ok_or(crate::dialeto::DialetoError::Vazio)?;
412
413        // Route the foreign-dialect rejection gate through the lifted
414        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
415        // typed predicate rather than the pre-lift hand-rolled three-arm
416        // `match { Pacote => {}, Desconhecido => {}, foreign => Err(…) }`
417        // literal — the `defmolde` declaration-family partition (the two-
418        // arity closure of [`crate::dialeto::CaixaDialeto::Molde`] and
419        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two arms
420        // whose sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
421        // projection already collapses onto `"defmolde"` and whose sibling
422        // [`crate::dialeto::CaixaDialeto::consumidor`] projection already
423        // collapses onto `"pleme-doc-gen"`) resolves through one dispatch
424        // on the substrate primitive. `Pacote` (the tatara-lisp package
425        // manifest this derive can parse) and `Desconhecido` (deliberately
426        // falls through to the derive rather than short-circuiting: a
427        // `(defcaixa …)` matching neither schema is most likely a genuine
428        // package manifest with a typo in `:nome`, and the derive's
429        // diagnostic — which names the offending keyword and suggests the
430        // nearest slot — is far better than anything this classifier
431        // could say) both return `false` from `is_molde_family()` and fall
432        // through to the derive. Only the typed dialect flows into the
433        // error — the three user-facing projections (canonical keyword,
434        // description, consumer) are read at Display time through
435        // [`crate::dialeto::CaixaDialeto`]'s own accessors, so the
436        // variant cannot carry a snapshot that drifts from
437        // [`crate::dialeto::CaixaDialeto::palavra_canonica`] /
438        // `descricao` / `consumidor`. A future fifth dialect the
439        // [`crate::dialeto`] module doc's "third dialect" hazard
440        // actualises that belongs to the `defmolde` family lands one
441        // match arm at [`crate::dialeto::CaixaDialeto::is_molde_family`]
442        // and this gate picks up the new arm by construction — the pre-
443        // lift wildcard `foreign =>` was compile-time-anonymous and would
444        // silently absorb any hypothetical fifth `defcaixa`-family arm as
445        // foreign; routing the partition through the typed predicate
446        // closes both drift surfaces.
447        let dialeto = crate::dialeto::classify_form(first)?;
448        if dialeto.is_molde_family() {
449            return Err(LeituraError::dialeto_estrangeiro(dialeto));
450        }
451
452        Self::compile_from_sexp(first).map_err(LeituraError::Leitura)
453    }
454
455    /// Register `Caixa` with the global tatara-lisp domain registry so
456    /// `defcaixa` is dispatchable from any tatara-lisp binary that seeds
457    /// the registry (e.g. `tatara-check`).
458    ///
459    /// Returns the typed [`tatara_lisp::KeywordCollision`] on the second
460    /// (and every subsequent) call in the same process — one keyword,
461    /// one type, per process is a hard invariant of the upstream
462    /// registry, and a caller that hits it must fix its crate graph
463    /// rather than swallowing the error. Peer of the sibling per-crate
464    /// `register()` entry points at `caixa-flake/src/flake.rs`,
465    /// `caixa-fmt/src/lisp_config.rs`, `caixa-lacre/src/lock.rs`,
466    /// `caixa-lint/src/lisp_config.rs`, `caixa-resolver/src/lisp_config.rs`
467    /// — every substrate crate that owns a tatara-lisp keyword now
468    /// propagates the same typed error verbatim, so a downstream binary
469    /// that seeds the registry (`tatara-check`, the future LSP) reaches
470    /// for one shape at every call site.
471    ///
472    /// # Errors
473    ///
474    /// [`tatara_lisp::KeywordCollision`] when a peer type has already
475    /// claimed the `defcaixa` keyword in this process.
476    pub fn register() -> Result<(), tatara_lisp::KeywordCollision> {
477        tatara_lisp::domain::register::<Self>()
478    }
479
480    /// Substrate-canonical per-`Caixa` `:licenca` SPDX-expression scalar
481    /// accessor every consumer of the top-level manifest's license axis
482    /// keys off — returns the author-declared `:licenca` byte-string
483    /// verbatim as an `Option<&str>`, borrowed from the typed slot's own
484    /// `Option<String>` storage. `None` when the slot is absent (the
485    /// canonical "omit to defer to the caixa-helm renderer's `MIT`
486    /// fallback" shape [`Self::validate_licenca`] documents at
487    /// caixa-core/src/manifest.rs:1560; the peer [`caixa-helm`]
488    /// `build_readme` fold at caixa-helm/src/lib.rs:962 reads this
489    /// predicate too, so an authored-but-unset `:licenca` round-trips to
490    /// a rendered `lareira-<nome>` chart's `README.md` `## License`
491    /// section structurally identical to one that omits the slot).
492    ///
493    /// The `:licenca` slot carries the universal-axis SPDX-expression
494    /// license identifier every kind of caixa emits under (CAIXA-SDLC
495    /// §I — the author-facing surface every `defcaixa` form supplies) —
496    /// the typed slot's `Option<String>` accept-set (empty-string
497    /// rejected through [`ManifestError::LicencaEmpty`], SPDX-alphabet-
498    /// invalid rejected through [`ManifestError::LicencaInvalid`]) maps
499    /// onto the `lareira-<nome>` Helm chart's `README.md` `## License`
500    /// section (caixa-helm/src/lib.rs:962) and (through future
501    /// tightening documented at [`Self::validate_licenca`]) the
502    /// Chart.yaml `annotations["artifacthub.io/license"]` axis every
503    /// registry-facing chart carries. Every downstream consumer that
504    /// reads the license byte-string keys off this scalar (the
505    /// [`Self::validate_licenca`] empty-arm + SPDX-shape gate that
506    /// routes through `self.licenca.as_deref()`, the caixa-helm
507    /// `build_readme` `unwrap_or_else(|| "MIT".into())` fold that keys
508    /// the fallback off the `Option::is_none()` arm, every future
509    /// per-`Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
510    /// acknowledges).
511    ///
512    /// Prior to this lift the `.licenca` field was accessed inline at
513    /// two production sites — [`Self::validate_licenca`]'s
514    /// `self.licenca.as_deref()` empty-and-shape gate binding and the
515    /// caixa-helm `build_readme` `caixa.licenca.clone().unwrap_or_else(||
516    /// "MIT".into())` `README.md` `## License` fold — two open-coded
517    /// field-accesses that expressed no compile-time link back to the
518    /// typed slot. A future extension of the `:licenca` axis to a
519    /// richer author surface — a per-`:licenca` structured SPDX
520    /// expression parser + license-id allowlist (the future tightening
521    /// [`Self::validate_licenca`]'s docstring acknowledges), a
522    /// per-cluster license-default overlay the M4 CR materializer
523    /// resolves per-CR (the "cluster policy pins `Apache-2.0` for every
524    /// unlisted caixa" arm), a promotion of the plain
525    /// `Option<String>` byte-string to a richer `SpdxExpression` enum
526    /// once the SPDX-expression parser lands — would have had to be
527    /// threaded through both open-coded copies in lockstep or the
528    /// validate gate and the caixa-helm emit path would silently
529    /// disagree on which license a given [`Caixa`] resolves to (an
530    /// author's `:licenca "MIT OR Apache-2.0"` would satisfy validate
531    /// while the emit path silently rendered a stale `MIT` fallback,
532    /// or vice versa). Lifting the resolution to a typed method on the
533    /// substrate primitive means every downstream consumer of the
534    /// caixa's per-`Caixa` license surface reaches for exactly one
535    /// typed dispatch — the resolver's accept-set migrates as a unit
536    /// on any future axis addition.
537    ///
538    /// First `Option<&str>`-return top-level [`Caixa`] scalar accessor —
539    /// opens the "outer [`Caixa`] `Option<&str>` scalar" projection
540    /// pattern the sibling per-`Caixa` `:descricao` / `:repositorio` /
541    /// `:edicao` future lifts fold on. Same "one typed dispatch on the
542    /// substrate primitive, thin projections at each consumer"
543    /// discipline the peer per-`:placement` [`crate::aplicacao::Placement::shard_key`]
544    /// (7cd2a28) / [`crate::aplicacao::Placement::affinity`] (74ec2d3)
545    /// / per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
546    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
547    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
548    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
549    /// typed-slot atom axes, extended here to the outer top-level
550    /// `Caixa` universal-axis surface. Named `licenca()` to match the
551    /// storage field's name; the accessor's identity maps onto the
552    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
553    /// carries.
554    #[must_use]
555    pub const fn licenca(&self) -> Option<&str> {
556        match &self.licenca {
557            Some(s) => Some(s.as_str()),
558            None => None,
559        }
560    }
561
562    /// Substrate-canonical per-`Caixa` `:repositorio` git-repo-URL scalar
563    /// accessor every consumer of the top-level manifest's homepage /
564    /// source-of-truth axis keys off — returns the author-declared
565    /// `:repositorio` byte-string verbatim as an `Option<&str>`, borrowed
566    /// from the typed slot's own `Option<String>` storage. `None` when
567    /// the slot is absent (the canonical "omit to defer to the renderer's
568    /// per-target placeholder" shape — [`caixa-helm`]'s `ChartYaml.home`
569    /// carries the `Option<String>` through verbatim so an author-omitted
570    /// `:repositorio` renders a `Chart.yaml` without a `home:` field
571    /// (`skip_serializing_if = "Option::is_none"`), while [`caixa-flux`]'s
572    /// `ClusterBundleOpts::for_caixa` folds the omitted slot through a
573    /// `format!("https://github.com/{DEFAULT_PLEME_GIT_ORG}/{nome}")`
574    /// fallback derived from `caixa.nome`).
575    ///
576    /// The `:repositorio` slot carries the universal-axis git-repo-URL
577    /// homepage identifier every kind of caixa emits under (CAIXA-SDLC
578    /// §I — the author-facing surface every `defcaixa` form supplies) —
579    /// the typed slot's `Option<String>` accept-set (empty-string
580    /// rejected through [`ManifestError::RepositorioEmpty`], git-repo-URL-
581    /// shape-invalid rejected through [`ManifestError::RepositorioInvalid`]
582    /// past the shared [`crate::render::is_git_repo_url`] predicate the
583    /// peer per-`:deps :fonte :repo` axis also routes through) maps onto
584    /// four load-bearing downstream consumers:
585    ///
586    ///   - [`Self::validate_repositorio`]'s empty-arm + shape-predicate
587    ///     gate binding at caixa-core/src/manifest.rs:1456 — the
588    ///     universal-axis identity gate wired at caixa-build time.
589    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.home` fold at
590    ///     caixa-helm/src/lib.rs:840 — the rendered `lareira-<nome>`
591    ///     Helm chart's `Chart.yaml` `home:` field, which every registry
592    ///     that ingests the chart (ArtifactHub, chartmuseum,
593    ///     `helm search repo`) surfaces as the chart's canonical source-
594    ///     of-truth link.
595    ///   - [`caixa-helm`]'s `build_readme` `## Source` fold at
596    ///     caixa-helm/src/lib.rs:957 — the rendered `lareira-<nome>`
597    ///     chart's `README.md` header link back to the source repo,
598    ///     which every author who inspects the rendered chart bundle
599    ///     lands at.
600    ///   - [`caixa-flux`]'s `ClusterBundleOpts::for_caixa`
601    ///     `GitRepository.spec.url` fold at caixa-flux/src/lib.rs:2006 —
602    ///     the rendered `GitRepository` CR's `spec.url` field, which
603    ///     FluxCD's `source-controller` polls to reconcile the caixa's
604    ///     manifest bundle from git.
605    ///
606    /// Prior to this lift the `.repositorio` field was accessed inline
607    /// at four production sites — [`Self::validate_repositorio`]'s
608    /// `self.repositorio.as_deref()` empty-and-shape gate binding, the
609    /// caixa-helm `build_chart_yaml` `caixa.repositorio.clone()`
610    /// `Chart.yaml` `home:` field fold, the caixa-helm `build_readme`
611    /// `caixa.repositorio.clone().unwrap_or_else(|| caixa.nome.clone())`
612    /// `README.md` `## Source` fold, and the caixa-flux
613    /// `ClusterBundleOpts::for_caixa`
614    /// `caixa.repositorio.clone().unwrap_or_else(|| format!(...))`
615    /// `GitRepository.spec.url` fold — four open-coded field-accesses
616    /// that expressed no compile-time link back to the typed slot. A
617    /// future extension of the `:repositorio` axis to a richer author
618    /// surface — a per-`:repositorio` structured
619    /// [`crate::render::GitRepoUrl`]-shaped scheme+host+path parse
620    /// (the future tightening [`Self::validate_repositorio`]'s
621    /// docstring anticipates alongside the peer per-`:deps :fonte
622    /// :repo` axis), a per-cluster repo-mirror overlay the M4 CR
623    /// materializer resolves per-CR (the "cluster policy rewrites
624    /// `github:pleme-io/...` to `git.internal/mirror/pleme-io/...`"
625    /// arm the private-registry story acknowledges), a promotion of
626    /// the plain `Option<String>` byte-string to a richer
627    /// `RepoUrl` enum discriminated on scheme — would have had to be
628    /// threaded through all four open-coded copies in lockstep or the
629    /// validate gate and the three emit paths would silently disagree
630    /// on which URL a given [`Caixa`] resolves to (an author's
631    /// `:repositorio "github:pleme-io/checkout"` would satisfy validate
632    /// while one of the emit paths silently rendered a stale URL, or
633    /// vice versa). Lifting the resolution to a typed method on the
634    /// substrate primitive means every downstream consumer of the
635    /// caixa's per-`Caixa` repo-URL surface reaches for exactly one
636    /// typed dispatch — the resolver's accept-set migrates as a unit on
637    /// any future axis addition.
638    ///
639    /// Second outer top-level [`Caixa`] `Option<&str>`-return scalar
640    /// accessor — sibling of [`Self::licenca`] (6d5bc28), the accessor
641    /// that opened the "outer [`Caixa`] `Option<&str>` scalar"
642    /// projection pattern this lift folds on. Same "one typed dispatch
643    /// on the substrate primitive, thin projections at each consumer"
644    /// discipline the peer per-`:placement`
645    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
646    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
647    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
648    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
649    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
650    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
651    /// typed-slot atom axes, extended here to the second outer top-level
652    /// `Caixa` universal-axis surface. Named `repositorio()` to match
653    /// the storage field's name; the accessor's identity maps onto the
654    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
655    /// carries.
656    #[must_use]
657    pub const fn repositorio(&self) -> Option<&str> {
658        match &self.repositorio {
659            Some(s) => Some(s.as_str()),
660            None => None,
661        }
662    }
663
664    /// Substrate-canonical per-`Caixa` **resolved-git-repo-URL** composer —
665    /// returns the caixa's canonical git-source-of-truth URL as an owned
666    /// [`String`], author-declared `:repositorio` byte-string verbatim on
667    /// the `Some` arm and the substrate's canonical pleme-org github URL
668    /// fallback ([`crate::DEFAULT_PLEME_GIT_ORG`] and [`Self::nome`]
669    /// interpolated into `https://github.com/<org>/<nome>`) on the
670    /// `None` arm. Every substrate-side consumer that resolves
671    /// "which git URL does this caixa's source live at?" reaches for
672    /// exactly one typed dispatch on the substrate primitive — the raw
673    /// `caixa.repositorio().map(str::to_owned).unwrap_or_else(|| format!(
674    /// "https://github.com/{org}/{nome}", org = DEFAULT_PLEME_GIT_ORG,
675    /// nome = caixa.nome()))` open-coded composition every prior caller
676    /// re-derived collapses onto one canonical arm.
677    ///
678    /// Distinct from [`Self::repositorio`] (`Option<&str>`, exposes the
679    /// author-omitted / author-declared partition to the caller) — this
680    /// accessor is the **resolved** URL surface, folding the fallback in
681    /// at the substrate-primitive boundary. Every consumer that keys off
682    /// the `Option::is_none()` discriminator (a [`Chart.yaml`] `home:`
683    /// field emit that must omit the field entirely on an author-omitted
684    /// `:repositorio`, per the [`Self::repositorio`] docstring's
685    /// documented four-consumer list) reaches through the raw
686    /// [`Self::repositorio`] `Option<&str>` accessor by construction — the
687    /// resolved-URL composer sits alongside it as the second projection
688    /// on the same underlying `:repositorio` slot rather than replacing
689    /// the raw accessor.
690    ///
691    /// The fallback branch is the exact byte-image of the prior inline
692    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url` composer at
693    /// caixa-flux/src/lib.rs:2080 — pinned by the sibling caixa-flux
694    /// byte-parity test
695    /// `cluster_bundle_opts_for_caixa_git_url_routes_through_canonical_git_url_accessor`
696    /// against a future implementation of this method that reordered the
697    /// `format!` template arguments, migrated the `<org>` segment to a
698    /// different constant (the [`crate::DEFAULT_PLEME_GIT_ORG`] axis a
699    /// future substrate-side git-org migration may split off), or
700    /// silently absorbed the empty-string arm (a hypothetical
701    /// `Some("") → fallback` collapse the raw [`Self::repositorio`]
702    /// accessor's docstring explicitly rejects on the sibling raw
703    /// accessor).
704    ///
705    /// Peer of the sibling per-`&Caixa`-axis composed helpers
706    /// [`caixa-flux::cluster_bundle_for_caixa`] (06d52d7) on the sibling
707    /// substrate-side renderer surface — same "close the composed
708    /// substrate-primitive at one canonical arm on the single-`&Caixa`
709    /// dispatch, converge every prior open-coded caller onto the arm"
710    /// discipline extended onto the resolved-git-URL projection of the
711    /// per-`Caixa` `:repositorio` axis. Owns per-call [`String`]
712    /// allocation on both arms (the `Some` arm's `str::to_owned` and the
713    /// `None` arm's `format!`) — the by-value return matches every
714    /// downstream consumer's field-fill shape (the caixa-flux
715    /// `ClusterBundleOpts::git_url: String` field, every future
716    /// `Chart.yaml` `home:` fold's `Option<String>` field-fill on the
717    /// `Some` arm).
718    #[must_use]
719    pub fn canonical_git_url(&self) -> String {
720        self.repositorio().map_or_else(
721            || {
722                format!(
723                    "https://github.com/{org}/{nome}",
724                    org = crate::DEFAULT_PLEME_GIT_ORG,
725                    nome = self.nome(),
726                )
727            },
728            str::to_owned,
729        )
730    }
731
732    /// Substrate-canonical per-`Caixa` **resolved-publish-tag** composer —
733    /// returns the caixa's canonical Zig-style git-publish-tag as an owned
734    /// [`String`], derived by concatenating
735    /// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] with the typed
736    /// [`Self::versao`] byte-string on a single `format!` template.
737    /// Every substrate-side consumer that resolves "which git tag does this
738    /// caixa publish under?" reaches for exactly one typed dispatch on the
739    /// substrate primitive — the raw `format!("{prefix}{versao}", prefix =
740    /// caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao = caixa.versao())`
741    /// open-coded composition every prior caller re-derived collapses onto
742    /// one canonical arm.
743    ///
744    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
745    /// git-URL composer on the paired per-`Caixa` git-remote axis — same
746    /// "close the composed substrate-primitive at one canonical arm on the
747    /// single-`&Caixa` dispatch, converge every prior open-coded caller
748    /// onto the arm" discipline extended from the resolved-URL projection
749    /// of the per-`Caixa` `:repositorio` axis onto the resolved-tag
750    /// projection of the per-`Caixa` `:versao` axis. The two accessors
751    /// jointly close the pair of scalars every `FluxCD` `GitRepository` CR
752    /// keys off (`spec.url` via [`Self::canonical_git_url`],
753    /// `spec.ref.tag` via [`Self::publish_tag`]) at the substrate primitive
754    /// — a downstream consumer that reaches through both accessors reads
755    /// the complete published-git-identity of a caixa through two typed
756    /// dispatches, not four open-coded field accesses.
757    ///
758    /// The reader-side (`caixa-flux::cluster_bundle` /
759    /// `ClusterBundleOpts::for_caixa`'s `git_ref` field, every future
760    /// per-cluster snapshot bundle emitter, the future M4
761    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's tag-carrier
762    /// slot on the tatara `Process` intent) always resolves the tag under
763    /// the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] prefix — this
764    /// method encodes that reader-side convention. The writer-side
765    /// (`caixa-feira`'s `feira publish` `--prefix` clap flag) allows the
766    /// operator to override the prefix at publish time; the two surfaces
767    /// intentionally sit on the "canonical default + operator override"
768    /// pair the sibling [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] constant's
769    /// own docstring documents — a `feira publish --prefix release/`
770    /// override is the operator's explicit opt-out from the substrate
771    /// default, not a supported drift axis.
772    ///
773    /// The composition body is the exact byte-image of the prior inline
774    /// [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_ref` composer at
775    /// caixa-flux/src/lib.rs:2105 — pinned by the sibling caixa-flux
776    /// byte-parity test
777    /// `cluster_bundle_opts_for_caixa_git_ref_routes_through_publish_tag_accessor`
778    /// against a future implementation of this method that reordered the
779    /// `format!` template arguments, migrated the `<prefix>` segment to a
780    /// different constant (the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] axis
781    /// a future Zig-style-tag rebrand may split off — the constant's own
782    /// docstring anticipates a substrate-side move to `release/<versao>`
783    /// or bare `<versao>` shapes once a sibling forge convention adopts a
784    /// slash-namespaced or bare-scalar form), interposed a canonicalization
785    /// pass on the `:versao` axis (a SemVer-2 build-metadata strip an OCI-
786    /// tag normalizer might apply once the M4 registry-alignment slot
787    /// lands), or silently absorbed an empty `:versao` arm (which cannot
788    /// occur past the [`Self::validate_versao`] gate but which a
789    /// hypothetical bypass on the accessor path must not silently paper
790    /// over).
791    ///
792    /// Owns per-call [`String`] allocation via the single `format!`
793    /// invocation — the by-value return matches every downstream
794    /// consumer's field-fill shape (the caixa-flux `GitRefSpec::Tag(String)`
795    /// variant's owned payload, every future `intent.aplicacao.tag: String`
796    /// field-fill on the M4 CR materializer's tag-carrier slot).
797    #[must_use]
798    pub fn publish_tag(&self) -> String {
799        format!(
800            "{prefix}{versao}",
801            prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
802            versao = self.versao(),
803        )
804    }
805
806    /// Substrate-canonical per-`Caixa` **resolved-Helm-chart-name** composer
807    /// — returns the caixa's canonical `lareira-<nome>` per-Servico Helm
808    /// chart identity as an owned [`String`], derived by dispatching through
809    /// the substrate-canonical [`crate::lareira_chart_name`] helper against
810    /// the typed [`Self::nome`] byte-string. Every substrate-side consumer
811    /// that resolves "which Helm chart identity does this caixa render
812    /// under?" reaches for exactly one typed dispatch on the substrate
813    /// primitive — the raw `caixa_core::lareira_chart_name(caixa.nome())`
814    /// two-step compose every prior caller re-derived collapses onto one
815    /// canonical arm on the single-`&Caixa` dispatch.
816    ///
817    /// Peer of the sibling [`Self::canonical_git_url`] (124f864) resolved-
818    /// git-URL composer + [`Self::publish_tag`] (07e05b8) resolved-publish-
819    /// tag composer on the paired per-`Caixa` published-artifact-identity
820    /// axis — same "close the composed substrate-primitive at one canonical
821    /// arm on the single-`&Caixa` dispatch, converge every prior open-coded
822    /// caller onto the arm" discipline extended from the resolved-URL /
823    /// resolved-tag projections of the `:repositorio` / `:versao` axes onto
824    /// the resolved-chart-name projection of the `:nome` axis. The three
825    /// accessors jointly close the triple of scalars every per-Servico
826    /// deploy artifact keys off (git source URL via
827    /// [`Self::canonical_git_url`], git source tag via
828    /// [`Self::publish_tag`], per-Servico Helm chart identity via
829    /// [`Self::lareira_chart_name`]) at the substrate primitive — a
830    /// downstream consumer that reaches through all three reads the
831    /// complete deploy-artifact identity of a caixa through three typed
832    /// dispatches, not six open-coded compositions across three renderer
833    /// crates.
834    ///
835    /// The reader-side (three production sites at the time of the lift —
836    /// [`caixa-helm::render_chart_for_servico_with`]'s `ChartDir.name`
837    /// composer at caixa-helm/src/lib.rs:778, the peer
838    /// [`caixa-flux::cluster_bundle`]'s per-CR `chart_name` binding at
839    /// caixa-flux/src/lib.rs:2219, and
840    /// [`caixa-tatara::process_for_aplicacao`]'s `release_name`
841    /// composer at caixa-tatara/src/lib.rs:227, plus every future
842    /// per-Servico OCI publish emitter the CAIXA-SDLC §II
843    /// `caixa-publish.yml` reusable workflow's `skopeo push` step keys
844    /// off, the future per-cluster snapshot bundle emitter, the future
845    /// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
846    /// per-member chart-carrier slot on the tatara `Process` intent) —
847    /// always resolves the chart name under the canonical
848    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] prefix; this method encodes
849    /// that reader-side convention. The joint-length invariant the peer
850    /// [`Self::validate_nome_chart_name_budget`] gate enforces at
851    /// caixa-build time (author-declared `:nome` + fixed prefix ≤
852    /// [`crate::DNS_1123_LABEL_MAX_LEN`]) is verified on the input to
853    /// this composer by construction, so the produced `lareira-<nome>`
854    /// string is a valid Helm chart-name segment on every accept-set
855    /// input.
856    ///
857    /// The composition body is the exact byte-image of the prior inline
858    /// `caixa_core::lareira_chart_name(caixa.nome())` two-step form every
859    /// prior caller re-derived — pinned by the sibling caixa-helm /
860    /// caixa-flux / caixa-tatara byte-parity tests
861    /// `<crate>_lareira_chart_name_routes_through_caixa_accessor` against
862    /// a future implementation of this method that reordered the
863    /// composition arguments, migrated the `<prefix>` segment to a
864    /// different constant (the [`crate::LAREIRA_CHART_NAME_PREFIX`] axis a
865    /// future substrate-side chart-family rebrand may split off — the
866    /// constant's own docstring anticipates a substrate-side move once
867    /// the `lareira-` scoping intent outlives the family it names),
868    /// interposed a canonicalization pass on the `:nome` axis (a per-
869    /// registry namespace-qualification an M4 CR materializer might apply
870    /// per-CR — the "`pleme-io/checkout` vs `partner-org/checkout`
871    /// collision" arm the multi-tenant-registry story acknowledges), or
872    /// silently absorbed an empty `:nome` arm (which cannot occur past
873    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
874    /// on the accessor path must not silently paper over).
875    ///
876    /// Owns per-call [`String`] allocation via the single
877    /// [`crate::lareira_chart_name`] `format!` invocation — the by-value
878    /// return matches every downstream consumer's field-fill shape (the
879    /// caixa-helm `ChartDir.name: String` field, the caixa-flux per-CR
880    /// `chart_name: String` binding, the caixa-tatara
881    /// `AplicacaoIntent.release_name: Option<String>` field-fill on the
882    /// `Some` arm).
883    #[must_use]
884    pub fn lareira_chart_name(&self) -> String {
885        crate::lareira_chart_name(self.nome())
886    }
887
888    /// Substrate-canonical per-`Caixa` **resolved-OCI-chart-ref** composer
889    /// — returns the caixa's canonical `oci://<registry>/lareira-<nome>`
890    /// per-Servico Helm chart OCI artifact reference as an owned
891    /// [`String`], derived by dispatching through the substrate-canonical
892    /// [`crate::oci_chart_ref`] helper (which itself composes
893    /// [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied `registry` +
894    /// [`crate::lareira_chart_name`]-of-[`Self::nome`]) against the
895    /// caller-supplied `registry` and the typed [`Self::nome`] byte-string.
896    /// Every substrate-side consumer that resolves "which OCI chart
897    /// artifact does this caixa publish under, in this registry?" reaches
898    /// for exactly one typed dispatch on the substrate primitive — the raw
899    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step compose
900    /// every prior caller re-derived collapses onto one canonical arm on
901    /// the single-`(&Caixa, &str)` dispatch.
902    ///
903    /// Fourth member of the paired per-`Caixa` published-artifact-identity
904    /// axis alongside [`Self::canonical_git_url`] (124f864) /
905    /// [`Self::publish_tag`] (07e05b8) / [`Self::lareira_chart_name`]
906    /// (a8f0bee) — same "close the composed substrate-primitive at one
907    /// canonical arm on the single-`&Caixa` dispatch, converge every
908    /// prior open-coded caller onto the arm" discipline extended from the
909    /// resolved-URL / resolved-tag / resolved-chart-name projections of
910    /// the `:repositorio` / `:versao` / `:nome` axes onto the resolved-
911    /// OCI-ref projection over the paired `(registry, :nome)` inputs. The
912    /// four accessors jointly close the per-`Caixa` published-artifact-
913    /// identity surface every downstream consumer of a caixa's published
914    /// deploy artifacts keys off (git source URL via
915    /// [`Self::canonical_git_url`], git source tag via
916    /// [`Self::publish_tag`], per-Servico Helm chart identity via
917    /// [`Self::lareira_chart_name`], per-registry OCI chart artifact
918    /// reference via [`Self::oci_chart_ref`]) at the substrate primitive
919    /// — a downstream consumer that reaches through all four reads the
920    /// complete deploy-artifact identity of a caixa through four typed
921    /// dispatches, not eight open-coded compositions across four renderer
922    /// crates. The unique-signature dispatch (`(&Caixa, &str)` on this
923    /// method vs. `&Caixa` on the sibling three) reflects the extra input
924    /// axis this composer folds in: unlike the git-URL / git-tag / chart-
925    /// name axes (each derived purely from a `&Caixa`), the OCI-ref axis
926    /// pairs the caixa's per-`:nome` chart identity with the caller-
927    /// supplied per-registry authority segment, so the accessor threads
928    /// the registry byte-string through as a positional `&str`.
929    ///
930    /// The reader-side (one production site at the time of the lift —
931    /// [`caixa-tatara::process_for_aplicacao`]'s `derive_chart_ref` helper
932    /// at caixa-tatara/src/lib.rs:333 that composes the emitted
933    /// `AplicacaoIntent.chart_ref` scalar the tatara-reconciler feeds into
934    /// `helm install`, plus every future per-Servico OCI publish emitter
935    /// the CAIXA-SDLC §II `caixa-publish.yml` reusable workflow's
936    /// `skopeo push` step keys off, the future per-cluster snapshot bundle
937    /// emitter's per-CR `oci://…` field-fill on the M4 registry-alignment
938    /// slot, the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
939    /// materializer's per-member `chart_ref` slot on the tatara `Process`
940    /// intent, the `FluxCD` `HelmRelease` `spec.chart.spec.chart` field-fill
941    /// on the OCI-source path an M4 per-cluster registry-rewrite overlay
942    /// applies per-CR) — always resolves the OCI ref under the canonical
943    /// [`crate::OCI_SCHEME_PREFIX`] scheme prefix + the canonical
944    /// [`Self::lareira_chart_name`] chart-name segment; this method
945    /// encodes that reader-side convention.
946    ///
947    /// The composition body is the exact byte-image of the prior inline
948    /// `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step form
949    /// every prior caller re-derived — pinned by the sibling caixa-tatara
950    /// byte-parity test
951    /// `derive_chart_ref_routes_through_caixa_oci_chart_ref_accessor`
952    /// against a future implementation of this method that reordered the
953    /// composition arguments, migrated the `<scheme>` segment to a
954    /// different constant (the [`crate::OCI_SCHEME_PREFIX`] axis a future
955    /// substrate-side registry-protocol rebrand may split off — the
956    /// constant's own docstring anticipates a substrate-side move once
957    /// Helm 3 / `FluxCD` introduce a successor scheme past `oci://`),
958    /// migrated the `<chart>` segment off the paired
959    /// [`crate::lareira_chart_name`] composer (a per-registry
960    /// namespace-qualification an M4 CR materializer might apply per-CR),
961    /// interposed a canonicalization pass on the `registry` axis (an OCI-
962    /// authority normalization once the M4 registry-alignment slot lands),
963    /// or silently absorbed an empty `:nome` arm (which cannot occur past
964    /// the [`Self::validate_nome`] gate but which a hypothetical bypass
965    /// on the accessor path must not silently paper over).
966    ///
967    /// Owns per-call [`String`] allocation via the single
968    /// [`crate::oci_chart_ref`] `format!` invocation — the by-value return
969    /// matches every downstream consumer's field-fill shape (the caixa-
970    /// tatara `AplicacaoIntent.chart_ref: String` field-fill, every
971    /// future `intent.aplicacao.chart_ref: String` field-fill on the M4
972    /// CR materializer's chart-ref-carrier slot, every future
973    /// `HelmRelease.spec.chart.spec.chart: String` field-fill on the OCI-
974    /// source path).
975    #[must_use]
976    pub fn oci_chart_ref(&self, registry: &str) -> String {
977        crate::oci_chart_ref(registry, self.nome())
978    }
979
980    /// Substrate-canonical per-`Caixa` `:descricao` free-form-prose
981    /// chart-description scalar accessor every consumer of the top-level
982    /// manifest's Chart.yaml `description:` axis keys off — returns the
983    /// author-declared `:descricao` byte-string verbatim as an
984    /// `Option<&str>`, borrowed from the typed slot's own
985    /// `Option<String>` storage. `None` when the slot is absent (the
986    /// canonical "omit to defer to the per-renderer `caixa.nome`-derived
987    /// fallback" shape — [`caixa-helm`]'s `build_chart_yaml` folds the
988    /// omitted slot through a `format!("Generated chart for caixa Servico
989    /// {}", caixa.nome)` fallback, [`caixa-helm`]'s `build_readme` folds
990    /// it through a `format!("caixa Servico {}", caixa.nome)` fallback,
991    /// and [`caixa-feira`]'s `render_flake` folds it through a
992    /// `format!("caixa {}", c.nome)` `flake.nix` `description = ""`
993    /// fallback — each derived from `caixa.nome` on the null-carrier arm).
994    ///
995    /// The `:descricao` slot carries the universal-axis free-form-prose
996    /// chart-description identifier every kind of caixa emits under
997    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa` form
998    /// supplies) — the typed slot's `Option<String>` accept-set
999    /// (empty-string rejected through [`ManifestError::DescricaoEmpty`],
1000    /// chart-description-shape-invalid rejected through
1001    /// [`ManifestError::DescricaoInvalid`] past the shared
1002    /// [`crate::render::is_chart_description_shape`] predicate the peer
1003    /// per-`Caixa` `:descricao` axis also routes through) maps onto four
1004    /// load-bearing downstream consumers:
1005    ///
1006    ///   - [`Self::validate_descricao`]'s empty-arm + shape-predicate
1007    ///     gate binding — the universal-axis identity gate wired at
1008    ///     caixa-build time.
1009    ///   - [`caixa-helm`]'s `build_chart_yaml` `ChartYaml.description`
1010    ///     `Chart.yaml` field fold — the rendered `lareira-<nome>` Helm
1011    ///     chart's `Chart.yaml` `description:` field, which
1012    ///     `apiVersion: v2` charts require non-empty (`helm lint` fires
1013    ///     `WARNING [chart.metadata.description]: description is required`
1014    ///     when absent) and which every registry that ingests the chart
1015    ///     (ArtifactHub, chartmuseum, `helm search repo`) surfaces as the
1016    ///     chart's canonical one-line prose descriptor.
1017    ///   - [`caixa-helm`]'s `build_readme` chart-`README.md` header fold
1018    ///     — the rendered `lareira-<nome>` chart's `README.md` prose
1019    ///     header directly beneath the `# <chart-name>` title, which
1020    ///     every author who inspects the rendered chart bundle lands at.
1021    ///   - [`caixa-feira`]'s `render_flake` `flake.nix` `description = ""`
1022    ///     top-level fold — the emitted `flake.nix`'s `description`
1023    ///     field, which every Nix consumer (`nix flake show`,
1024    ///     `nix flake metadata`, downstream flake-registry ingestors)
1025    ///     surfaces as the flake's canonical descriptor.
1026    ///
1027    /// Prior to this lift the `.descricao` field was accessed inline at
1028    /// four production sites — [`Self::validate_descricao`]'s
1029    /// `self.descricao.as_deref()` empty-and-shape gate binding, the
1030    /// caixa-helm `build_chart_yaml`
1031    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
1032    /// `Chart.yaml` `description:` fold, the caixa-helm `build_readme`
1033    /// `caixa.descricao.clone().unwrap_or_else(|| format!(...))`
1034    /// `README.md` header fold, and the caixa-feira `render_flake`
1035    /// `c.descricao.clone().unwrap_or_else(|| format!(...))` `flake.nix`
1036    /// `description = ""` fold — four open-coded field-accesses that
1037    /// expressed no compile-time link back to the typed slot. A future
1038    /// extension of the `:descricao` axis to a richer author surface —
1039    /// a per-`:descricao` locale-tagged multi-language descriptor map
1040    /// (the "one caixa, N language-tagged prose descriptions" arm
1041    /// author-tooling internationalization anticipates), a
1042    /// per-registry-target length-and-shape overlay the M4 CR
1043    /// materializer resolves per-CR (the "ArtifactHub caps description
1044    /// at 512 bytes but the internal registry caps at 256" arm), a
1045    /// promotion of the plain `Option<String>` byte-string to a richer
1046    /// `ChartDescription` newtype guaranteeing the
1047    /// `is_chart_description_shape` predicate at the type level — would
1048    /// have had to be threaded through all four open-coded copies in
1049    /// lockstep or the validate gate and the three emit paths would
1050    /// silently disagree on which prose string a given [`Caixa`]
1051    /// resolves to (an author's
1052    /// `:descricao "Checkout flow orchestration."` would satisfy
1053    /// validate while one of the emit paths silently rendered a stale
1054    /// `caixa.nome`-derived fallback, or vice versa). Lifting the
1055    /// resolution to a typed method on the substrate primitive means
1056    /// every downstream consumer of the caixa's per-`Caixa`
1057    /// chart-description surface reaches for exactly one typed dispatch
1058    /// — the resolver's accept-set migrates as a unit on any future
1059    /// axis addition.
1060    ///
1061    /// Third outer top-level [`Caixa`] `Option<&str>`-return scalar
1062    /// accessor — sibling of [`Self::licenca`] (6d5bc28) and
1063    /// [`Self::repositorio`] (cc7332d), the accessors that opened the
1064    /// "outer [`Caixa`] `Option<&str>` scalar" projection pattern this
1065    /// lift folds on. Same "one typed dispatch on the substrate
1066    /// primitive, thin projections at each consumer" discipline the
1067    /// peer per-`:placement`
1068    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1069    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1070    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1071    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1072    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1073    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1074    /// typed-slot atom axes, extended here to the third outer top-level
1075    /// `Caixa` universal-axis surface. Named `descricao()` to match the
1076    /// storage field's name; the accessor's identity maps onto the
1077    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1078    /// carries. The one remaining universal `Option<String>` slot
1079    /// (`:edicao`) folds on this pattern next.
1080    #[must_use]
1081    pub const fn descricao(&self) -> Option<&str> {
1082        match &self.descricao {
1083            Some(s) => Some(s.as_str()),
1084            None => None,
1085        }
1086    }
1087
1088    /// Substrate-canonical per-`Caixa` `:edicao` language-edition scalar
1089    /// accessor every consumer of the top-level manifest's tatara-lisp
1090    /// edition-selector axis keys off — returns the author-declared
1091    /// `:edicao` byte-string verbatim as an `Option<&str>`, borrowed from
1092    /// the typed slot's own `Option<String>` storage. `None` when the
1093    /// slot is absent (the canonical "omit the slot to defer to the
1094    /// substrate's default edition" shape every existing
1095    /// [`caixa-resolver`] integration test fixture carries via
1096    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`;
1097    /// the peer [`Self::validate_edicao`] gate is a no-op on the omitted
1098    /// arm by construction, so an author-omitted `:edicao` round-trips
1099    /// to a build without triggering the year-shape predicate).
1100    ///
1101    /// The `:edicao` slot carries the universal-axis 4-digit-ASCII-
1102    /// decimal-year language-edition identifier every kind of caixa
1103    /// emits under (CAIXA-SDLC §I — the author-facing surface every
1104    /// `defcaixa` form supplies) — the typed slot's `Option<String>`
1105    /// accept-set (empty-string rejected through
1106    /// [`ManifestError::EdicaoEmpty`], year-shape-invalid rejected
1107    /// through [`ManifestError::EdicaoInvalid`] past the 4-digit-ASCII-
1108    /// decimal-year predicate [`Self::validate_edicao`] enforces) maps
1109    /// onto one load-bearing downstream consumer today
1110    /// ([`Self::validate_edicao`]'s empty-arm + year-shape-predicate
1111    /// gate binding at caixa-core/src/manifest.rs:1959) plus every
1112    /// future edition-aware substrate consumer the CAIXA-SDLC §I
1113    /// roadmap anticipates (the tatara-lisp compiler's macro-surface
1114    /// selector every edition-aware build step keys off, the future
1115    /// per-edition compatibility-flag overlay the M4 CR materializer
1116    /// resolves per-CR, the peer [`Caixa::template`] canonical
1117    /// `:edicao "2026"` scaffold every `feira init` emits verbatim,
1118    /// and the renderer-side fixtures at `caixa-helm/src/lib.rs:978` /
1119    /// `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208` that
1120    /// carry `edicao: Some("2026".into())` by construction).
1121    ///
1122    /// Prior to this lift the `.edicao` field was accessed inline at
1123    /// one production site — [`Self::validate_edicao`]'s
1124    /// `self.edicao.as_deref()` empty-and-shape gate binding — one
1125    /// open-coded field-access that expressed no compile-time link
1126    /// back to the typed slot. A future extension of the `:edicao`
1127    /// axis to a richer author surface — a per-`:edicao` known-
1128    /// edition allowlist (the future tightening
1129    /// [`Self::validate_edicao`]'s docstring acknowledges past the
1130    /// structural year-shape floor, rejecting year-shaped values that
1131    /// don't name a tatara-lisp edition the substrate actually
1132    /// understands — `"1999"` is year-shaped but no `1999` edition
1133    /// exists), a per-edition compatibility-flag overlay the M4 CR
1134    /// materializer resolves per-CR (the "edition `"2026"` enables
1135    /// macro-surface features the sibling `"2018"` gates behind a
1136    /// feature flag" arm the edition-selector story anticipates), a
1137    /// promotion of the plain `Option<String>` byte-string to a
1138    /// richer `CaixaEdition` enum discriminated on year once a sibling
1139    /// edition to `"2026"` lands — would have had to be threaded
1140    /// through the open-coded copy in lockstep with every future
1141    /// edition-aware consumer, or the validate gate and the future
1142    /// edition-aware consumer path would silently disagree on which
1143    /// edition a given [`Caixa`] resolves to (an author's
1144    /// `:edicao "2026"` would satisfy validate while a future
1145    /// edition-aware consumer silently defaulted to a stale edition,
1146    /// or vice versa). Lifting the resolution to a typed method on
1147    /// the substrate primitive means every downstream consumer of the
1148    /// caixa's per-`Caixa` edition surface reaches for exactly one
1149    /// typed dispatch — the resolver's accept-set migrates as a unit
1150    /// on any future axis addition.
1151    ///
1152    /// Fourth and final outer top-level [`Caixa`] `Option<&str>`-return
1153    /// scalar accessor — sibling of [`Self::licenca`] (6d5bc28),
1154    /// [`Self::repositorio`] (cc7332d), and [`Self::descricao`]
1155    /// (3f16e2f), the accessors that opened the "outer [`Caixa`]
1156    /// `Option<&str>` scalar" projection pattern this lift folds on.
1157    /// Same "one typed dispatch on the substrate primitive, thin
1158    /// projections at each consumer" discipline the peer per-`:placement`
1159    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
1160    /// [`crate::aplicacao::Placement::affinity`] (74ec2d3) /
1161    /// per-`:contratos` [`crate::aplicacao::WitContract::endpoint`]
1162    /// (7020470) / [`crate::aplicacao::WitContract::subject`] (90de675)
1163    /// / [`crate::aplicacao::WitContract::slot`] (ed22b66)
1164    /// `Option<&str>`-return accessors carry on the sibling M2 / M3
1165    /// typed-slot atom axes, extended here to close the outer top-level
1166    /// `Caixa` universal-axis surface's last unlifted `Option<String>`
1167    /// slot. Named `edicao()` to match the storage field's name; the
1168    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1169    /// vocabulary the slot's docstring already carries.
1170    #[must_use]
1171    pub const fn edicao(&self) -> Option<&str> {
1172        match &self.edicao {
1173            Some(s) => Some(s.as_str()),
1174            None => None,
1175        }
1176    }
1177
1178    /// Substrate-canonical per-`Caixa` `:nome` universal-axis DNS-1123-
1179    /// label caixa-identity scalar accessor every consumer of the top-
1180    /// level manifest's identity axis keys off — returns the author-
1181    /// declared `:nome` byte-string verbatim as an `&str`, borrowed from
1182    /// the typed slot's own `String` storage. Non-optional (`:nome` is
1183    /// a required-axis scalar every `defcaixa` form must supply; the
1184    /// [`Self::from_lisp`] derive rejects an omitted / non-string
1185    /// `:nome` at parse time, so a `Caixa` past parse definitionally
1186    /// carries a non-`None` `:nome`).
1187    ///
1188    /// The `:nome` slot carries the universal-axis DNS-1123-label
1189    /// caixa-identity every kind of caixa emits under (CAIXA-SDLC §I —
1190    /// the primary identity axis every `defcaixa` form supplies
1191    /// alongside `:versao` / `:kind`; the substrate-wide identity every
1192    /// other typed surface that names a caixa reaches through — `:deps`
1193    /// entries, `:membros` entries, `:children` entries, the
1194    /// `lareira-<nome>` Helm chart name every per-Servico renderer
1195    /// derives, the `pleme-program-<nome>` label every per-Aplicacao
1196    /// renderer emits) — the typed slot's `String` accept-set (empty
1197    /// rejected through [`ManifestError::NomeEmpty`], DNS-1123-shape-
1198    /// invalid rejected through [`ManifestError::NomeInvalid`] past
1199    /// the shared [`crate::render::require_valid_dns_1123_label`] gate
1200    /// the peer name axes each land on, joint-length-with-`lareira-`-
1201    /// prefix rejected through
1202    /// [`ManifestError::NomeChartNameBudgetExceeded`] past
1203    /// [`crate::render::is_lareira_chart_name_shape`]) maps onto every
1204    /// load-bearing downstream consumer the substrate carries — the
1205    /// two universal-axis validate gates at caixa-build time
1206    /// ([`Self::validate_nome`] + [`Self::validate_nome_chart_name_budget`]),
1207    /// [`crate::lareira_chart_name`]'s `lareira-<nome>` Helm chart-name
1208    /// derivation every per-Servico renderer keys off, the caixa-helm
1209    /// `Chart.yaml`'s `name:` axis, caixa-flux's `programs.yaml` entry
1210    /// `name:` axis, caixa-mesh's Cilium `CiliumNetworkPolicy` /
1211    /// `HTTPRoute` per-Aplicacao name axes at
1212    /// caixa-mesh/src/lib.rs:{2650, 2797, 2919, 2925},
1213    /// [`crate::pleme_program_selector`] /
1214    /// [`crate::pleme_program_in_aplicacao_selector`] label-selector
1215    /// derivations, and every future substrate renderer that emits an
1216    /// artifact keyed by the caixa's identity.
1217    ///
1218    /// Prior to this lift the `.nome` field was accessed inline at a
1219    /// dozen production sites across `caixa-core` (the two universal-
1220    /// axis validate gates + [`Dep::validate`]-adjacent duplicate
1221    /// tracking), `caixa-helm` (the `lareira_chart_name` fold, the
1222    /// `ChartYaml.name` / `ChartYaml.description` / `Chart.yaml`
1223    /// `keywords` fallback), `caixa-flux` (the `programs.yaml`
1224    /// entry `name:` fold, the `flux_kustomization_source_subtree`
1225    /// per-cluster subpath derivation), and `caixa-mesh` (the
1226    /// `pleme_program_in_aplicacao_selector` label-selector fold, the
1227    /// `cilium_network_policy_name` / `gateway_api_http_route_name`
1228    /// per-CR name derivations, the `LABEL_APLICACAO` labels-map
1229    /// insert) — a dozen open-coded field-accesses that expressed no
1230    /// compile-time link back to the typed slot. A future extension of
1231    /// the `:nome` axis to a richer author surface — a per-`:nome`
1232    /// structured `CaixaIdentity` newtype that carries the joint-
1233    /// length-with-prefix invariant [`Self::validate_nome_chart_name_budget`]
1234    /// enforces at the type level (rather than as a validate-time
1235    /// gate), a per-registry `:nome` namespacing overlay the M4 CR
1236    /// materializer resolves per-CR (the "`pleme-io/checkout` vs
1237    /// `partner-org/checkout` collision" arm the multi-tenant-registry
1238    /// story acknowledges), a promotion of the plain `String` byte-
1239    /// string to a richer `CaixaNome` newtype discriminated on
1240    /// namespace prefix — would have had to be threaded through every
1241    /// open-coded copy in lockstep or the two validate gates and the
1242    /// dozen emit paths would silently disagree on which identity a
1243    /// given [`Caixa`] resolves to (an author's `:nome "checkout"`
1244    /// would satisfy validate while one of the emit paths silently
1245    /// rendered a drifted other identity, or vice versa). Lifting the
1246    /// resolution to a typed method on the substrate primitive means
1247    /// every downstream consumer of the caixa's per-`Caixa` identity
1248    /// surface reaches for exactly one typed dispatch — the resolver's
1249    /// accept-set migrates as a unit on any future axis addition.
1250    ///
1251    /// First outer top-level [`Caixa`] `&str`-return required-scalar
1252    /// accessor — opens the "outer [`Caixa`] `&str` required-scalar"
1253    /// projection pattern the sibling per-`Caixa` `:versao` future lift
1254    /// folds on. Sibling in shape to the peer per-`:membros`
1255    /// [`crate::aplicacao::Membro::nome`] (4a32abf) / per-`:contratos`
1256    /// [`crate::aplicacao::WitContract::source`] /
1257    /// [`crate::aplicacao::WitContract::destination`] (7f0fd43),
1258    /// [`crate::aplicacao::WitContract::world_ref`] (0804823),
1259    /// [`crate::aplicacao::Membro::versao_requirement`] (a40b0e3),
1260    /// [`crate::aplicacao::Entrada::destination`] (6db982c),
1261    /// [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062),
1262    /// per-sub-struct required-axis accessors carry on the sibling M3
1263    /// mesh-slot-atom scalar-value axes, extended here to open the
1264    /// outer top-level [`Caixa`] `&str`-return required-scalar surface.
1265    /// Named `nome()` to match the storage field's name; the accessor's
1266    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1267    /// slot's docstring already carries.
1268    #[must_use]
1269    pub const fn nome(&self) -> &str {
1270        self.nome.as_str()
1271    }
1272
1273    /// Substrate-canonical per-`Caixa` `:versao` universal-axis SemVer-2
1274    /// pinned-version scalar accessor every consumer of the top-level
1275    /// manifest's version axis keys off — returns the author-declared
1276    /// `:versao` byte-string verbatim as an `&str`, borrowed from the
1277    /// typed slot's own `String` storage. Non-optional (`:versao` is a
1278    /// required-axis scalar every `defcaixa` form must supply alongside
1279    /// `:nome` / `:kind`; the [`Self::from_lisp`] derive rejects an
1280    /// omitted / non-string `:versao` at parse time, so a `Caixa` past
1281    /// parse definitionally carries a non-`None` `:versao`).
1282    ///
1283    /// The `:versao` slot carries the universal-axis SemVer-2
1284    /// concrete-version body every kind of caixa emits under
1285    /// (CAIXA-SDLC §I — the required-scalar every `defcaixa` form
1286    /// supplies alongside `:nome` / `:kind`; the substrate-wide
1287    /// pinned-version every downstream artifact-emitting consumer
1288    /// composes under — the `lareira-<nome>` Helm chart's `Chart.yaml`
1289    /// `version:` + `appVersion:` axes, the `feira publish` Zig-style
1290    /// `v<versao>` git tag the [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
1291    /// prefix composes on top of, the programs.yaml entry's `versao:`
1292    /// value the `lareira-fleet-programs` aggregator carries onto each
1293    /// rendered `ComputeUnit`, the OCI image's `:v<versao>` / `:latest`
1294    /// tags every substrate-side `skopeo push` writes, the lacre
1295    /// closure's pinned `concrete_versao`, and the `:upgrade-from :from`
1296    /// prior-version references peers in the exact same SemVer-2 shape).
1297    /// The typed slot's `String` accept-set (empty rejected through
1298    /// [`ManifestError::VersaoEmpty`], SemVer-2-shape-invalid rejected
1299    /// through [`ManifestError::VersaoInvalid`] past
1300    /// [`semver::Version::parse`]) maps onto every load-bearing
1301    /// downstream consumer the substrate carries — the [`Self::validate_versao`]
1302    /// universal-axis validate gate at caixa-build time, the
1303    /// [`crate::CaixaVersion::parse`] typed-wrapper resolver,
1304    /// [`caixa-helm`]'s `Chart.yaml` `version:` / `appVersion:` fold,
1305    /// [`caixa-flux`]'s `programs.yaml` entry `versao:` fold + the
1306    /// `cluster_bundle` `GitRepository` `ref: { tag: v<versao> }`
1307    /// derivation, [`caixa-mesh`]'s per-Aplicacao `programs.yaml` fan-
1308    /// out entry `versao:` fold, [`caixa-feira`]'s `feira publish` git-
1309    /// tag derivation (`format!("{prefix}{versao}")`), and every future
1310    /// substrate renderer that emits an artifact keyed by the caixa's
1311    /// pinned version.
1312    ///
1313    /// Prior to this lift the `.versao` field was accessed inline at a
1314    /// dozen production sites across `caixa-core` (the universal-axis
1315    /// [`Self::validate_versao`] gate + [`Dep::validate`]-adjacent
1316    /// version-shape gates), `caixa-helm` (the `ChartYaml.version` /
1317    /// `ChartYaml.app_version` folds), `caixa-flux` (the `programs.yaml`
1318    /// entry `versao:` fold, the `cluster_bundle` `GitRepository` `ref:
1319    /// { tag: v<versao> }` derivation), `caixa-mesh` (the per-Aplicacao
1320    /// `programs.yaml` fan-out entry `versao:` fold), and `caixa-feira`
1321    /// (the `feira publish` git-tag derivation + the `feira app graph` /
1322    /// `feira app deploy` diagnostic renderers) — a dozen open-coded
1323    /// field-accesses that expressed no compile-time link back to the
1324    /// typed slot. A future extension of the `:versao` axis to a richer
1325    /// author surface — a per-`:versao` structured `CaixaVersion` at the
1326    /// storage layer (the substrate already carries a `CaixaVersion`
1327    /// newtype at [`crate::version::CaixaVersion`], deferred until the
1328    /// serde-transparent-newtype-through-DeriveTataraDomain path lands),
1329    /// a per-registry `:versao` immutability overlay the M4 CR
1330    /// materializer enforces per-CR, a promotion of the plain `String`
1331    /// byte-string to a richer `PinnedVersao` newtype discriminated on
1332    /// SemVer-2 pre-release / build-metadata presence — would have had
1333    /// to be threaded through every open-coded copy in lockstep or the
1334    /// validate gate and the dozen emit paths would silently disagree
1335    /// on which version a given [`Caixa`] resolves to (an author's
1336    /// `:versao "0.1.0"` would satisfy validate while one of the emit
1337    /// paths silently rendered a drifted other version, or vice versa).
1338    /// Lifting the resolution to a typed method on the substrate
1339    /// primitive means every downstream consumer of the caixa's
1340    /// per-`Caixa` pinned-version surface reaches for exactly one typed
1341    /// dispatch — the resolver's accept-set migrates as a unit on any
1342    /// future axis addition.
1343    ///
1344    /// Second outer top-level [`Caixa`] `&str`-return required-scalar
1345    /// accessor — folds on the "outer [`Caixa`] `&str` required-scalar"
1346    /// projection pattern the sibling per-`Caixa` [`Self::nome`]
1347    /// (e6b7d97) opened. Sibling in shape to the peer per-`:membros`
1348    /// [`crate::aplicacao::Membro::versao_requirement`] (4127bb6) /
1349    /// per-`:children` [`crate::supervisor::ChildSpec::versao_requirement`]
1350    /// (2c053c8) / per-`:upgrade-from` [`crate::UpgradeFromEntry::prior_versao`]
1351    /// (75d27a8) per-sub-struct `:versao`-shaped `&str`-return accessors
1352    /// on the sibling per-typed-slot version-carrier axes, extended here
1353    /// to close the second outer top-level [`Caixa`] required-`&str`-
1354    /// carrying axis so the two universal-axis identity-carrying
1355    /// scalars every `defcaixa` form supplies (`:nome` + `:versao`)
1356    /// share the same "one typed dispatch per axis" discipline. Named
1357    /// `versao()` to match the storage field's name; the accessor's
1358    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
1359    /// slot's docstring already carries.
1360    #[must_use]
1361    pub const fn versao(&self) -> &str {
1362        self.versao.as_str()
1363    }
1364
1365    /// Substrate-canonical per-`Caixa` `:kind` universal-axis
1366    /// closed-set-enum discriminant accessor every consumer of the top-
1367    /// level manifest's kind axis keys off — returns the author-declared
1368    /// `:kind` variant verbatim as a [`CaixaKind`], `Copy`-projected
1369    /// from the typed slot's own [`CaixaKind`] storage. Non-optional
1370    /// (`:kind` is a required-axis discriminant every `defcaixa` form
1371    /// must supply alongside `:nome` / `:versao`; the [`Self::from_lisp`]
1372    /// derive rejects an omitted / non-symbol `:kind` at parse time, so
1373    /// a `Caixa` past parse definitionally carries a valid [`CaixaKind`]
1374    /// variant).
1375    ///
1376    /// The `:kind` slot carries the universal-axis closed-set typed-
1377    /// discriminant every substrate-side dispatch keys off (CAIXA-SDLC
1378    /// §I — the primary shape gate every renderer / verifier /
1379    /// operator branches on; the five variants `Biblioteca` /
1380    /// `Binario` / `Servico` / `Supervisor` / `Aplicacao` partition
1381    /// the caixa surface into disjoint runtime contracts) — the typed
1382    /// slot's [`CaixaKind`] accept-set (parse-time-rejected non-symbol
1383    /// values through the derive-macro's symbol-arm gate, exhaustively
1384    /// matched at every downstream dispatch site) maps onto every
1385    /// load-bearing downstream consumer the substrate carries:
1386    ///
1387    ///   - [`crate::render::require_kind`]'s per-renderer entry-gate
1388    ///     predicate — the canonical two-line
1389    ///     `require_kind(caixa, Servico)?` prelude every per-Servico
1390    ///     renderer (`caixa-helm`, `caixa-flux`, the future `caixa-otel`
1391    ///     / per-Servico OCI packager / M4 `wasm.pleme.io/v1alpha1/
1392    ///     ComputeUnit` CR materializer) runs at its entry-point,
1393    ///     alongside the [`crate::render::KindMismatch`] error carrier's
1394    ///     `actual:` field the diagnostic surfaces to name the offending
1395    ///     caixa's variant.
1396    ///   - [`Self::aplicacao_view`]'s + [`Self::supervisor_view`]'s
1397    ///     per-view kind-gate binding — the two `Option<TypedSpec>`
1398    ///     `_view` composers that fold the flat mesh-slot / supervisor-
1399    ///     slot columns into their typed sub-spec only when the kind
1400    ///     matches (returns `None` otherwise); the future per-Servico
1401    ///     M2-view composer (`servico_view`) will follow the same shape.
1402    ///   - [`Self::declared_foreign_code_slots`]'s per-slot kind-
1403    ///     coherence gate — the `!self.kind.requires_exe()` /
1404    ///     `!self.kind.requires_servicos()` predicates that fence
1405    ///     each code-surface slot from the wrong owning kind.
1406    ///   - [`crate::LayoutInvariants::verify`]'s kind ↔ code-surface
1407    ///     coherence gates — the six `caixa.kind == CaixaKind::X` /
1408    ///     `caixa.kind != CaixaKind::X` predicates and the four kind-
1409    ///     coherence error carriers (`SupervisorOwnsCode` /
1410    ///     `AplicacaoOwnsCode` / `MeshSlotsOnNonAplicacao` /
1411    ///     `SupervisorSlotsOnNonSupervisor` / `ServicoSlotsOnNonServico`
1412    ///     / `ForeignCodeSlot`) which each name the offending caixa's
1413    ///     variant in their `kind:` field.
1414    ///
1415    /// Prior to this lift the `.kind` field was accessed inline at
1416    /// twenty-plus production sites across `caixa-core` (the
1417    /// [`crate::render::require_kind`] entry-gate predicate + the
1418    /// [`crate::render::KindMismatch`] `actual:` field, the two `_view`
1419    /// composers, the `declared_foreign_code_slots` per-slot kind-
1420    /// coherence gate, and the six [`crate::LayoutInvariants::verify`]
1421    /// kind ↔ code-surface predicates + four error carriers) — a score
1422    /// of open-coded field-accesses that expressed no compile-time link
1423    /// back to the typed slot. A future extension of the `:kind` axis
1424    /// to a richer author surface — a per-`:kind` sub-variant discriminant
1425    /// (e.g. `Servico(ServicoRuntime)` splitting the current single
1426    /// variant across the wasm-component / legacy-container / native-
1427    /// binary runtime axes the M5 roadmap acknowledges), a per-cluster
1428    /// kind-overlay the M4 CR materializer resolves per-CR (the
1429    /// "cluster policy demotes `Aplicacao` to `Servico` on a single-
1430    /// tenant cluster" arm), a promotion of the plain [`CaixaKind`]
1431    /// enum to a richer `KindWithRuntime` discriminated on the
1432    /// component-model world axis — would have had to be threaded
1433    /// through every open-coded copy in lockstep or the entry gate,
1434    /// the view composers, and the layout invariants would silently
1435    /// disagree on which kind a given [`Caixa`] resolves to. Lifting
1436    /// the resolution to a typed method on the substrate primitive
1437    /// means every downstream consumer of the caixa's per-`Caixa`
1438    /// kind surface reaches for exactly one typed dispatch — the
1439    /// resolver's accept-set migrates as a unit on any future axis
1440    /// addition.
1441    ///
1442    /// First outer top-level [`Caixa`] `Copy`-return required-enum-
1443    /// discriminant accessor — opens the "outer [`Caixa`] `Copy`-return
1444    /// required-discriminant" projection pattern. Sibling in shape to
1445    /// the peer per-`:supervisor` [`crate::supervisor::SupervisorSpec::estrategia`]
1446    /// (eafb619), per-`:placement` [`crate::aplicacao::Placement::estrategia`]
1447    /// (921fe1b), and per-`:children` [`crate::supervisor::ChildSpec::restart`]
1448    /// (dfb4a81) `Copy`-return closed-set-enum discriminant accessors
1449    /// on the sibling nested-spec typed-slot discriminator axes,
1450    /// extended here to the outer top-level [`Caixa`] universal-axis
1451    /// surface. Named `kind()` to match the storage field's name;
1452    /// the accessor's identity maps onto the canonical CAIXA-SDLC §I
1453    /// vocabulary the slot's docstring already carries.
1454    #[must_use]
1455    pub const fn kind(&self) -> CaixaKind {
1456        self.kind
1457    }
1458
1459    /// Substrate-canonical per-`Caixa` `:autores` universal-axis
1460    /// maintainer-name-list slice-accessor every consumer of the top-
1461    /// level manifest's maintainer axis keys off — returns the author-
1462    /// declared `:autores` list verbatim as a `&[String]` slice-view over
1463    /// the same backing buffer the raw `self.autores.as_slice()` field
1464    /// access borrows from. Empty-list-carrying (`:autores` is a default-
1465    /// empty axis every `defcaixa` form supplies with an empty `()` when
1466    /// unset; the [`Self::from_lisp`] derive folds an omitted `:autores`
1467    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1468    /// parse definitionally carries a `Vec<String>` slot — possibly
1469    /// empty — and the returned `&[String]` degenerates to an empty
1470    /// slice on that arm without any silent `None` collapse).
1471    ///
1472    /// The `:autores` slot carries the universal-axis maintainer-name
1473    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
1474    /// facing surface every `defcaixa` form supplies alongside `:nome` /
1475    /// `:versao` / `:kind`; the substrate-wide contact-carrying axis
1476    /// every downstream registry-facing artifact emits under) — the
1477    /// typed slot's `Vec<String>` accept-set (empty-per-entry rejected
1478    /// through [`ManifestError::AutorEmpty`], non-chart-maintainer-shape
1479    /// rejected through [`ManifestError::AutorInvalid`], cross-entry
1480    /// duplicate rejected through [`ManifestError::AutorDuplicate`]) maps
1481    /// onto every load-bearing downstream consumer the substrate carries
1482    /// — the [`Self::validate_autores`] universal-axis empty-per-entry +
1483    /// shape + duplicate gate at caixa-core/src/manifest.rs, the
1484    /// caixa-helm `build_chart_yaml` `maintainers:` fold at
1485    /// caixa-helm/src/lib.rs that walks each entry into a `Maintainer {
1486    /// name, email: None }` record, every future per-`Caixa` registry-
1487    /// facing renderer the CAIXA-SDLC §I roadmap acknowledges (the
1488    /// future `artifacthub.io/maintainers` `Chart.yaml` annotation the
1489    /// caixa-helm docstring alludes to at [`Self::validate_licenca`],
1490    /// the future per-cluster author-notification overlay the M4 CR
1491    /// materializer resolves per-CR).
1492    ///
1493    /// Prior to this lift the `.autores` field was accessed inline at
1494    /// two production sites — [`Self::validate_autores`]'s `for autor
1495    /// in &self.autores` walk that gates every entry through
1496    /// [`ManifestError::AutorEmpty`] / `AutorInvalid` / `AutorDuplicate`,
1497    /// and the caixa-helm `build_chart_yaml` `caixa.autores.iter().map(|a|
1498    /// Maintainer { name: a.clone(), email: None }).collect()` fold that
1499    /// materializes every entry into a `Chart.yaml` `maintainers:` row —
1500    /// two open-coded field-accesses that expressed no compile-time link
1501    /// back to the typed slot. A future extension of the `:autores` axis
1502    /// to a richer author surface — a per-`:autores` structured
1503    /// `Maintainer { name, email, url }` at the storage layer once the
1504    /// substrate absorbs `artifacthub.io/maintainers`' name+email+url
1505    /// tuple, a per-registry `:autores` allowlist the M4 CR materializer
1506    /// enforces per-CR (the "cluster policy demands every author declare
1507    /// an on-file `mailto:` contact" arm), a promotion of the plain
1508    /// `Vec<String>` byte-string list to a richer
1509    /// `Vec<ChartMaintainer>` newtype discriminated on the RFC-5322
1510    /// `<name> [<email>]` grammar the `is_chart_maintainer_name_shape`
1511    /// predicate already resolves through — would have had to be
1512    /// threaded through both open-coded copies in lockstep or the
1513    /// validate gate and the caixa-helm emit path would silently
1514    /// disagree on which authors a given [`Caixa`] resolves to (an
1515    /// author's `:autores ("alice" "bob")` would satisfy validate while
1516    /// the caixa-helm emit path silently rendered a drifted other
1517    /// maintainer list, or vice versa). Lifting the resolution to a
1518    /// typed method on the substrate primitive means every downstream
1519    /// consumer of the caixa's per-`Caixa` maintainer surface reaches
1520    /// for exactly one typed dispatch — the resolver's accept-set
1521    /// migrates as a unit on any future axis addition.
1522    ///
1523    /// First outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1524    /// opens the "outer [`Caixa`] `&[T]` slice" projection pattern the
1525    /// sibling per-`Caixa` `:etiquetas` / `:deps` / `:deps-dev` / `:exe`
1526    /// / `:bibliotecas` / `:servicos` / `:upgrade-from` / `:children`
1527    /// future lifts fold on. Sibling in shape to the peer per-`:supervisor`
1528    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce), per-`:placement`
1529    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7), per-`:membros`
1530    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36), per-`:contratos`
1531    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1532    /// per-`:upgrade-from :instructions` [`crate::upgrade::UpgradeFromEntry::instructions`]
1533    /// (0137e5a) `&[T]`-return slice accessors on the sibling per-M2 /
1534    /// per-M3 typed-slot list axes, extended here to the outer top-level
1535    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1536    /// `&Vec<String>`) because every downstream consumer of the author
1537    /// list treats it as a read-only sequence — the slice-view is the
1538    /// narrowest borrow that supports every present + roadmapped consumer
1539    /// (`.iter()`, `.len()`, `.is_empty()`) without leaking the backing
1540    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
1541    /// reaches for (the storage-side `Vec` remains reachable through the
1542    /// `pub autores` field for the mutation-carrying serde round-trip and
1543    /// per-test fixture-mutation paths). Named `autores()` to match the
1544    /// storage field's name; the accessor's identity maps onto the
1545    /// canonical CAIXA-SDLC §I vocabulary the slot's docstring already
1546    /// carries.
1547    #[must_use]
1548    pub const fn autores(&self) -> &[String] {
1549        self.autores.as_slice()
1550    }
1551
1552    /// Substrate-canonical per-`Caixa` `:etiquetas` universal-axis
1553    /// registry-search-tag-list slice-accessor every consumer of the
1554    /// top-level manifest's topical-tag axis keys off — returns the
1555    /// author-declared `:etiquetas` list verbatim as a `&[String]`
1556    /// slice-view over the same backing buffer the raw
1557    /// `self.etiquetas.as_slice()` field access borrows from. Empty-
1558    /// list-carrying (`:etiquetas` is a default-empty axis every
1559    /// `defcaixa` form supplies with an empty `()` when unset; the
1560    /// [`Self::from_lisp`] derive folds an omitted `:etiquetas` through
1561    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1562    /// definitionally carries a `Vec<String>` slot — possibly empty —
1563    /// and the returned `&[String]` degenerates to an empty slice on
1564    /// that arm without any silent `None` collapse).
1565    ///
1566    /// The `:etiquetas` slot carries the universal-axis topical-tag
1567    /// list every kind of caixa emits under (CAIXA-SDLC §I — the
1568    /// author-facing surface every `defcaixa` form supplies alongside
1569    /// `:nome` / `:versao` / `:kind`; the substrate-wide registry-
1570    /// search-facing axis every downstream registry-facing artifact
1571    /// emits under) — the typed slot's `Vec<String>` accept-set
1572    /// (empty-per-entry rejected through [`ManifestError::EtiquetaEmpty`],
1573    /// non-chart-keyword-shape rejected through
1574    /// [`ManifestError::EtiquetaInvalid`], cross-entry duplicate
1575    /// rejected through [`ManifestError::EtiquetaDuplicate`]) maps onto
1576    /// every load-bearing downstream consumer the substrate carries —
1577    /// the [`Self::validate_etiquetas`] universal-axis empty-per-entry
1578    /// + shape + duplicate gate at caixa-core/src/manifest.rs, the
1579    /// caixa-helm `build_chart_yaml` `keywords:` fold at
1580    /// caixa-helm/src/lib.rs that walks each entry into the rendered
1581    /// `Chart.yaml` `keywords:` array (chained with the
1582    /// [`crate::LAREIRA_CHART_KEYWORDS`] substrate-wide floor set and
1583    /// dedup'd through a `BTreeSet` at emit time), every future per-
1584    /// `Caixa` registry-facing renderer the CAIXA-SDLC §I roadmap
1585    /// acknowledges (the future `artifacthub.io/keywords` `Chart.yaml`
1586    /// annotation, the future per-cluster tag-notification overlay the
1587    /// M4 CR materializer resolves per-CR).
1588    ///
1589    /// Prior to this lift the `.etiquetas` field was accessed inline at
1590    /// two production sites — [`Self::validate_etiquetas`]'s `for
1591    /// etiqueta in &self.etiquetas` walk that gates every entry through
1592    /// [`ManifestError::EtiquetaEmpty`] / `EtiquetaInvalid` /
1593    /// `EtiquetaDuplicate`, and the caixa-helm `build_chart_yaml`
1594    /// `caixa.etiquetas.iter().cloned().chain(...)` fold that
1595    /// materializes every entry into a `Chart.yaml` `keywords:` row —
1596    /// two open-coded field-accesses that expressed no compile-time
1597    /// link back to the typed slot. A future extension of the
1598    /// `:etiquetas` axis to a richer tag surface — a per-`:etiquetas`
1599    /// structured `ChartKeyword { name, uri, category }` at the storage
1600    /// layer once the substrate absorbs `artifacthub.io/keywords`
1601    /// richer tag tuple, a per-registry `:etiquetas` allowlist the M4
1602    /// CR materializer enforces per-CR (the "cluster policy demands
1603    /// every tag come from a substrate-approved taxonomy" arm), a
1604    /// promotion of the plain `Vec<String>` byte-string list to a
1605    /// richer `Vec<ChartKeyword>` newtype discriminated on the DNS-
1606    /// 1123-label-shaped grammar the `is_chart_keyword_shape` predicate
1607    /// already resolves through — would have had to be threaded through
1608    /// both open-coded copies in lockstep or the validate gate and the
1609    /// caixa-helm emit path would silently disagree on which tags a
1610    /// given [`Caixa`] resolves to (an author's `:etiquetas ("demo"
1611    /// "aplicacao")` would satisfy validate while the caixa-helm emit
1612    /// path silently rendered a drifted other keyword list, or vice
1613    /// versa). Lifting the resolution to a typed method on the
1614    /// substrate primitive means every downstream consumer of the
1615    /// caixa's per-`Caixa` topical-tag surface reaches for exactly one
1616    /// typed dispatch — the resolver's accept-set migrates as a unit
1617    /// on any future axis addition.
1618    ///
1619    /// Second outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1620    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1621    /// [`Self::autores`] (b5d813f) opened, sibling in shape and
1622    /// idiom. The remaining unlifted outer-`Caixa` slice-carrying axes
1623    /// (`:deps` / `:deps-dev` / `:exe` / `:bibliotecas` / `:servicos`
1624    /// / `:upgrade-from` / `:children` / `:membros` / `:contratos`)
1625    /// fold onto the same pattern in future lifts. Sibling in shape to
1626    /// the peer per-`:supervisor`
1627    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1628    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1629    /// (a6e18d7), per-`:membros`
1630    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1631    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1632    /// (0dcc926), and per-`:upgrade-from :instructions`
1633    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1634    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1635    /// typed-slot list axes, extended here to the outer top-level
1636    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1637    /// `&Vec<String>`) because every downstream consumer of the tag
1638    /// list treats it as a read-only sequence — the slice-view is the
1639    /// narrowest borrow that supports every present + roadmapped
1640    /// consumer (`.iter()`, `.len()`, `.is_empty()`) without leaking
1641    /// the backing `Vec`'s grow/push/reserve surface no consumer of
1642    /// the typed view reaches for (the storage-side `Vec` remains
1643    /// reachable through the `pub etiquetas` field for the mutation-
1644    /// carrying serde round-trip and per-test fixture-mutation paths).
1645    /// Named `etiquetas()` to match the storage field's name; the
1646    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1647    /// vocabulary the slot's docstring already carries.
1648    #[must_use]
1649    pub const fn etiquetas(&self) -> &[String] {
1650        self.etiquetas.as_slice()
1651    }
1652
1653    /// Substrate-canonical per-`Caixa` `:bibliotecas` universal-axis
1654    /// library-source-path-list slice-accessor every consumer of the
1655    /// top-level manifest's Biblioteca-source axis keys off — returns
1656    /// the author-declared `:bibliotecas` list verbatim as a
1657    /// `&[String]` slice-view over the same backing buffer the raw
1658    /// `self.bibliotecas.as_slice()` field access borrows from. Empty-
1659    /// list-carrying (`:bibliotecas` is a default-empty axis every
1660    /// `defcaixa` form supplies with an empty `()` when unset; the
1661    /// [`Self::from_lisp`] derive folds an omitted `:bibliotecas`
1662    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
1663    /// parse definitionally carries a `Vec<String>` slot — possibly
1664    /// empty — and the returned `&[String]` degenerates to an empty
1665    /// slice on that arm without any silent `None` collapse).
1666    ///
1667    /// The `:bibliotecas` slot carries the universal-axis lisp-library
1668    /// entry-path list every `:kind Biblioteca` caixa emits under
1669    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1670    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1671    /// substrate-wide library-carrier axis every downstream
1672    /// authoring-facing consumer keys off) — the typed slot's
1673    /// `Vec<String>` accept-set (empty-per-entry rejected through
1674    /// [`ManifestError::CodePathEmpty { slot: ":bibliotecas" }`],
1675    /// non-sandboxed-relative-shape rejected through
1676    /// [`ManifestError::CodePathShape`], non-`.lisp`-extension rejected
1677    /// through [`ManifestError::CodePathNonLispExtension`], cross-entry
1678    /// duplicate rejected through [`ManifestError::CodePathDuplicate`])
1679    /// maps onto every load-bearing downstream consumer the substrate
1680    /// carries — the [`crate::LayoutInvariants`] Biblioteca-arm
1681    /// empty-check + per-entry file-exists loop at
1682    /// caixa-core/src/layout.rs that gates each entry through
1683    /// [`crate::LayoutError::MissingLib`] / `MissingEntry`, the
1684    /// [`Self::validate_code_paths`] per-slot shape gate at
1685    /// caixa-core/src/manifest.rs that walks each entry through the
1686    /// sandbox-relative / `.lisp`-extension / cross-entry duplicate
1687    /// gates, the `feira build` per-entry `tatara_lisp::read` parse
1688    /// walk at caixa-feira/src/cmd/build.rs that phase-1-checks each
1689    /// declared library file for lexical / structural errors before
1690    /// downstream `importar` resolution, every future per-`Caixa`
1691    /// library-facing renderer the CAIXA-SDLC §I roadmap acknowledges
1692    /// (the future `tatara-lispc` compilation entry the docstring at
1693    /// caixa-feira/src/cmd/build.rs alludes to, the future per-cluster
1694    /// bytecode-caching overlay the M4 CR materializer resolves per-CR,
1695    /// the future `caixa-lsp` per-library semantic-token stream the
1696    /// caixa-lsp docstring roadmaps).
1697    ///
1698    /// Prior to this lift the `.bibliotecas` field was accessed inline
1699    /// at three production sites — [`crate::LayoutInvariants`]'s
1700    /// `caixa.bibliotecas.is_empty()` `MissingLib`-arm gate + `for p
1701    /// in &caixa.bibliotecas` `MissingEntry` walk that gates each
1702    /// declared library path through the on-disk-existence check,
1703    /// the compound-code-path `has_code = !caixa.bibliotecas.is_empty()
1704    /// || !caixa.exe.is_empty() || !caixa.servicos.is_empty()` OR-fold
1705    /// on the [`crate::LayoutError::SupervisorOwnsCode`] /
1706    /// `AplicacaoOwnsCode` kind-coherence gate, and the `feira build`
1707    /// per-entry `for entry in &caixa.bibliotecas` + `caixa.bibliotecas.
1708    /// len()` phase-1 tatara-lispc-precursor parse walk — three open-
1709    /// coded field-accesses that expressed no compile-time link back
1710    /// to the typed slot. A future extension of the `:bibliotecas`
1711    /// axis to a richer library surface — a per-`:bibliotecas`
1712    /// structured `BibliotecaEntry { path, edition, exports }` at the
1713    /// storage layer once the substrate absorbs the per-library
1714    /// language-edition + explicit-exports tuple the tatara-lisp
1715    /// module-system roadmap acknowledges, a per-registry
1716    /// `:bibliotecas` allowlist the M4 CR materializer enforces
1717    /// per-CR (the "cluster policy demands every biblioteca declare
1718    /// its own :edicao" arm), a promotion of the plain `Vec<String>`
1719    /// byte-string list to a richer `Vec<LibraryPath>` newtype
1720    /// discriminated on the `lib/<nome>.lisp`-shape grammar the
1721    /// [`crate::render::is_sandboxed_relative_path`] +
1722    /// [`crate::render::is_lisp_extension`] predicates already resolve
1723    /// through — would have had to be threaded through all three
1724    /// open-coded copies in lockstep or the layout gate, the shape
1725    /// validator, and the `feira build` phase-1 parse walk would
1726    /// silently disagree on which library paths a given [`Caixa`]
1727    /// resolves to (an author's `:bibliotecas ("lib/foo.lisp"
1728    /// "lib/bar.lisp")` would satisfy layout while `feira build`
1729    /// silently parsed a drifted other list, or vice versa). Lifting
1730    /// the resolution to a typed method on the substrate primitive
1731    /// means every downstream consumer of the caixa's per-`Caixa`
1732    /// library-source surface reaches for exactly one typed dispatch
1733    /// — the resolver's accept-set migrates as a unit on any future
1734    /// axis addition.
1735    ///
1736    /// Third outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1737    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1738    /// [`Self::autores`] (b5d813f) opened and [`Self::etiquetas`]
1739    /// (78c7d3c) folded on, sibling in shape and idiom. The remaining
1740    /// unlifted outer-`Caixa` slice-carrying axes (`:deps` /
1741    /// `:deps-dev` / `:exe` / `:servicos` / `:upgrade-from` /
1742    /// `:children` / `:membros` / `:contratos`) fold onto the same
1743    /// pattern in future lifts. Sibling in shape to the peer
1744    /// per-`:supervisor`
1745    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
1746    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
1747    /// (a6e18d7), per-`:membros`
1748    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
1749    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
1750    /// (0dcc926), and per-`:upgrade-from :instructions`
1751    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1752    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1753    /// typed-slot list axes, extended here to the outer top-level
1754    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1755    /// `&Vec<String>`) because every downstream consumer of the
1756    /// library-source list treats it as a read-only sequence — the
1757    /// slice-view is the narrowest borrow that supports every
1758    /// present + roadmapped consumer (`.iter()`, `.len()`,
1759    /// `.is_empty()`) without leaking the backing `Vec`'s
1760    /// grow/push/reserve surface no consumer of the typed view
1761    /// reaches for (the storage-side `Vec` remains reachable through
1762    /// the `pub bibliotecas` field for the mutation-carrying serde
1763    /// round-trip and per-test fixture-mutation paths). Named
1764    /// `bibliotecas()` to match the storage field's name; the
1765    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
1766    /// vocabulary the slot's docstring already carries.
1767    #[must_use]
1768    pub const fn bibliotecas(&self) -> &[String] {
1769        self.bibliotecas.as_slice()
1770    }
1771
1772    /// Substrate-canonical per-`Caixa` `:exe` universal-axis
1773    /// nix-built-executable-entry-path-list slice-accessor every consumer
1774    /// of the top-level manifest's Binario-executable axis keys off —
1775    /// returns the author-declared `:exe` list verbatim as a `&[String]`
1776    /// slice-view over the same backing buffer the raw
1777    /// `self.exe.as_slice()` field access borrows from. Empty-list-
1778    /// carrying (`:exe` is a default-empty axis every `defcaixa` form
1779    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
1780    /// derive folds an omitted `:exe` through `#[serde(default)]` to
1781    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
1782    /// `Vec<String>` slot — possibly empty — and the returned `&[String]`
1783    /// degenerates to an empty slice on that arm without any silent
1784    /// `None` collapse).
1785    ///
1786    /// The `:exe` slot carries the universal-axis nix-built executable
1787    /// entry-path list every `:kind Binario` caixa emits under
1788    /// (CAIXA-SDLC §I — the author-facing surface every `defcaixa`
1789    /// form supplies alongside `:nome` / `:versao` / `:kind`; the
1790    /// substrate-wide `exe/`-directory-fenced entry-carrier axis every
1791    /// downstream flake-build-facing consumer keys off) — the typed
1792    /// slot's `Vec<String>` accept-set (empty-per-entry rejected
1793    /// through [`ManifestError::CodePathEmpty { slot: ":exe" }`],
1794    /// non-sandboxed-relative-shape rejected through
1795    /// [`ManifestError::CodePathShape`], cross-entry duplicate rejected
1796    /// through [`ManifestError::CodePathDuplicate`], out-of-`exe/`-
1797    /// directory paths rejected past the layout's
1798    /// [`crate::LayoutError::ExeOutsideDir`] `starts_with` fence) maps
1799    /// onto every load-bearing downstream consumer the substrate carries
1800    /// — the [`crate::LayoutInvariants`] Binario-arm empty-check +
1801    /// per-entry file-exists + `exe/`-directory-fence loop at
1802    /// caixa-core/src/layout.rs that gates each entry through
1803    /// [`crate::LayoutError::BinarioWithoutExe`] / `MissingEntry` /
1804    /// `ExeOutsideDir`, the compound `has_code` OR-fold on the
1805    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1806    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1807    /// that fences code-surface slots off from the two no-code kinds,
1808    /// [`Self::declared_foreign_code_slots`]'s `!self.exe.is_empty()`
1809    /// arm on the [`crate::LayoutError::ForeignCodeSlot`] gate that
1810    /// fences the `:exe` code surface off from every non-Binario code-
1811    /// running kind, [`Self::validate_code_paths`]'s per-slot shape gate
1812    /// that walks each entry through the sandbox-relative / cross-entry
1813    /// duplicate gates, every future per-`Caixa` executable-facing
1814    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1815    /// `caixa-flake` per-Binario `packages.<system>.<nome>` derivation
1816    /// entry the caixa-flake docstring roadmaps, the future per-cluster
1817    /// `nix-store` overlay the M4 CR materializer resolves per-CR, the
1818    /// future `feira nix` per-executable Binario-target emit path).
1819    ///
1820    /// Prior to this lift the `.exe` field was accessed inline at three
1821    /// production sites — the compound-code-path `has_code =
1822    /// !caixa.bibliotecas().is_empty() || !caixa.exe.is_empty() ||
1823    /// !caixa.servicos.is_empty()` OR-fold on the
1824    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1825    /// `AplicacaoOwnsCode` kind-coherence gate, the Binario-arm
1826    /// `caixa.exe.is_empty()` [`crate::LayoutError::BinarioWithoutExe`]
1827    /// gate, the per-entry `for p in &caixa.exe`
1828    /// `MissingEntry`/`ExeOutsideDir` walk, and the
1829    /// [`Self::declared_foreign_code_slots`]'s
1830    /// `!self.exe.is_empty()` arm on the `ForeignCodeSlot` gate — four
1831    /// open-coded field-accesses that expressed no compile-time link
1832    /// back to the typed slot. A future extension of the `:exe` axis
1833    /// to a richer executable surface — a per-`:exe` structured
1834    /// `BinarioEntry { path, wrapper, capabilities }` at the storage
1835    /// layer once the substrate absorbs the per-executable
1836    /// nix-wrapper + linux-capabilities tuple the CAIXA-SDLC §I
1837    /// executable roadmap acknowledges, a per-registry `:exe` allowlist
1838    /// the M4 CR materializer enforces per-CR (the "cluster policy
1839    /// demands every Binario declare an explicit `:wrapper`" arm), a
1840    /// promotion of the plain `Vec<String>` byte-string list to a
1841    /// richer `Vec<ExecutablePath>` newtype discriminated on the
1842    /// `exe/<nome>`-shape grammar the layout's `starts_with(exe_dir)`
1843    /// fence already resolves through — would have had to be threaded
1844    /// through all four open-coded copies in lockstep or the layout
1845    /// gate, the shape validator, and the `feira nix` emit path would
1846    /// silently disagree on which executable paths a given [`Caixa`]
1847    /// resolves to (an author's `:exe ("exe/cli" "exe/serve")` would
1848    /// satisfy layout while `feira nix` silently packaged a drifted
1849    /// other list, or vice versa). Lifting the resolution to a typed
1850    /// method on the substrate primitive means every downstream
1851    /// consumer of the caixa's per-`Caixa` executable-source surface
1852    /// reaches for exactly one typed dispatch — the resolver's accept-
1853    /// set migrates as a unit on any future axis addition.
1854    ///
1855    /// Fourth outer top-level [`Caixa`] `&[T]`-return slice-accessor —
1856    /// folds on the "outer [`Caixa`] `&[T]` slice" projection pattern
1857    /// [`Self::autores`] (b5d813f) opened, [`Self::etiquetas`]
1858    /// (78c7d3c) folded on, and [`Self::bibliotecas`] (8a36c23) closed
1859    /// the universal-axis text-tag family of. Opens the outer-`Caixa`
1860    /// foreign-code-slot `&[T]` sub-family the sibling `:servicos`
1861    /// future lift closes onto (per the trio of code-surface list slots
1862    /// the [`Self::validate_code_paths`] per-slot dispatch tuple
1863    /// already carries — `:bibliotecas` + `:exe` + `:servicos`, of which
1864    /// `:bibliotecas` landed at 8a36c23 and `:servicos` remains as the
1865    /// last unlifted code-surface slot). Sibling in shape to the peer
1866    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
1867    /// (bc92bce), per-`:placement`
1868    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
1869    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
1870    /// (6c77e36), per-`:contratos`
1871    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
1872    /// per-`:upgrade-from :instructions`
1873    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
1874    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
1875    /// typed-slot list axes, extended here to the outer top-level
1876    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
1877    /// `&Vec<String>`) because every downstream consumer of the
1878    /// executable-source list treats it as a read-only sequence — the
1879    /// slice-view is the narrowest borrow that supports every
1880    /// present + roadmapped consumer (`.iter()`, `.len()`,
1881    /// `.is_empty()`) without leaking the backing `Vec`'s
1882    /// grow/push/reserve surface no consumer of the typed view
1883    /// reaches for (the storage-side `Vec` remains reachable through
1884    /// the `pub exe` field for the mutation-carrying serde
1885    /// round-trip and per-test fixture-mutation paths). Named `exe()`
1886    /// to match the storage field's name; the accessor's identity
1887    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
1888    /// docstring already carries.
1889    #[must_use]
1890    pub const fn exe(&self) -> &[String] {
1891        self.exe.as_slice()
1892    }
1893
1894    /// Substrate-canonical per-`Caixa` `:servicos` universal-axis
1895    /// ComputeUnit-CR-YAML-entry-path-list slice-accessor every consumer
1896    /// of the top-level manifest's Servico-component axis keys off —
1897    /// returns the author-declared `:servicos` list verbatim as a
1898    /// `&[String]` slice-view over the same backing buffer the raw
1899    /// `self.servicos.as_slice()` field access borrows from. Empty-list-
1900    /// carrying (`:servicos` is a default-empty axis every `defcaixa`
1901    /// form supplies with an empty `()` when unset; the
1902    /// [`Self::from_lisp`] derive folds an omitted `:servicos` through
1903    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
1904    /// definitionally carries a `Vec<String>` slot — possibly empty —
1905    /// and the returned `&[String]` degenerates to an empty slice on
1906    /// that arm without any silent `None` collapse).
1907    ///
1908    /// The `:servicos` slot carries the universal-axis
1909    /// `.computeunit.yaml` ComputeUnit-CR entry-path list every
1910    /// `:kind Servico` caixa emits under (CAIXA-SDLC §I — the
1911    /// author-facing surface every `defcaixa` form supplies alongside
1912    /// `:nome` / `:versao` / `:kind`; the substrate-wide
1913    /// `servicos/`-directory-fenced entry-carrier axis every downstream
1914    /// Servico-facing renderer keys off) — the typed slot's
1915    /// `Vec<String>` accept-set (empty-per-entry rejected through
1916    /// [`ManifestError::CodePathEmpty { slot: ":servicos" }`],
1917    /// non-sandboxed-relative-shape rejected through
1918    /// [`ManifestError::CodePathShape`], non-`.computeunit.yaml`
1919    /// extension rejected through
1920    /// [`ManifestError::CodePathNonComputeUnitYamlExtension`], cross-
1921    /// entry duplicate rejected through
1922    /// [`ManifestError::CodePathDuplicate`], `len != 1` rejected by the
1923    /// V0 [`crate::ServicoCountMismatch`] gate on the per-Servico
1924    /// renderer entry-points, out-of-`servicos/`-directory paths
1925    /// rejected past the layout's [`crate::LayoutError::ServicoOutsideDir`]
1926    /// `starts_with` fence) maps onto every load-bearing downstream
1927    /// consumer the substrate carries — the [`crate::LayoutInvariants`]
1928    /// Servico-arm empty-check + per-entry file-exists + `servicos/`-
1929    /// directory-fence loop at caixa-core/src/layout.rs that gates each
1930    /// entry through [`crate::LayoutError::ServicoWithoutServicos`] /
1931    /// `MissingEntry` / `ServicoOutsideDir`, the compound `has_code`
1932    /// OR-fold on the [`crate::LayoutError::SupervisorOwnsCode`] /
1933    /// [`crate::LayoutError::AplicacaoOwnsCode`] kind-coherence gate
1934    /// that fences code-surface slots off from the two no-code kinds,
1935    /// [`Self::declared_foreign_code_slots`]'s
1936    /// `!self.servicos.is_empty()` arm on the
1937    /// [`crate::LayoutError::ForeignCodeSlot`] gate that fences the
1938    /// `:servicos` code surface off from every non-Servico code-running
1939    /// kind, [`Self::validate_code_paths`]'s per-slot shape gate that
1940    /// walks each entry through the sandbox-relative / `.computeunit.
1941    /// yaml`-extension / cross-entry duplicate gates, the
1942    /// [`crate::require_single_servico`] V0 singularity gate every
1943    /// per-Servico renderer entry-point runs through
1944    /// [`crate::require_v0_servico_shape`], the `feira chart` /
1945    /// `feira deploy` per-verb `first_servico_path` walk at
1946    /// caixa-feira/src/cmd/chart.rs that resolves the singleton
1947    /// ComputeUnit-CR file, every future per-`Caixa` Servico-facing
1948    /// renderer the CAIXA-SDLC §I roadmap acknowledges (the future
1949    /// per-Servico OCI packager, the future M4
1950    /// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer, the future
1951    /// per-Servico OTel collector-config emit).
1952    ///
1953    /// Prior to this lift the `.servicos` field was accessed inline at
1954    /// five production sites — the compound-code-path `has_code =
1955    /// !caixa.bibliotecas().is_empty() || !caixa.exe().is_empty() ||
1956    /// !caixa.servicos.is_empty()` OR-fold on the
1957    /// [`crate::LayoutError::SupervisorOwnsCode`] /
1958    /// `AplicacaoOwnsCode` kind-coherence gate, the Servico-arm
1959    /// `caixa.servicos.is_empty()`
1960    /// [`crate::LayoutError::ServicoWithoutServicos`] gate, the
1961    /// per-entry `for p in &caixa.servicos`
1962    /// `MissingEntry`/`ServicoOutsideDir` walk, the
1963    /// [`Self::declared_foreign_code_slots`]'s
1964    /// `!self.servicos.is_empty()` arm on the `ForeignCodeSlot` gate,
1965    /// and the [`crate::require_single_servico`] V0 count gate's
1966    /// `caixa.servicos.len() == 1` / `caixa.servicos.len()` count
1967    /// projection (both the accept-arm predicate and the
1968    /// diagnostic-carrying `ServicoCountMismatch { count }`
1969    /// projection) — five open-coded field-accesses across three
1970    /// crates that expressed no compile-time link back to the typed
1971    /// slot. A future extension of the `:servicos` axis to a richer
1972    /// component surface — a per-`:servicos` structured
1973    /// `ServicoEntry { path, world, capabilities }` at the storage
1974    /// layer once the substrate absorbs the per-component WIT-world +
1975    /// capability-set tuple the CAIXA-SDLC §I Servico roadmap
1976    /// acknowledges, a per-registry `:servicos` allowlist the M4 CR
1977    /// materializer enforces per-CR (the "cluster policy demands every
1978    /// Servico declare an explicit `:world`" arm), a promotion of the
1979    /// plain `Vec<String>` byte-string list to a richer
1980    /// `Vec<ComputeUnitPath>` newtype discriminated on the
1981    /// `servicos/<nome>.computeunit.yaml`-shape grammar the layout's
1982    /// `starts_with(servicos_dir)` fence and the
1983    /// [`crate::render::is_computeunit_yaml_extension`] predicate
1984    /// already resolve through, a promotion of the V0 singleton
1985    /// contract to a multi-component `Vec<ComputeUnitPath>` past the M5
1986    /// component-model multi-world boundary — would have had to be
1987    /// threaded through all five open-coded copies in lockstep or the
1988    /// layout gate, the shape validator, the V0 count gate, and the
1989    /// `feira chart` / `feira deploy` entry-point walks would silently
1990    /// disagree on which ComputeUnit-CR paths a given [`Caixa`]
1991    /// resolves to (an author's `:servicos ("servicos/foo.computeunit.
1992    /// yaml")` would satisfy layout while `feira chart` silently
1993    /// packaged a drifted other list, or vice versa). Lifting the
1994    /// resolution to a typed method on the substrate primitive means
1995    /// every downstream consumer of the caixa's per-`Caixa`
1996    /// ComputeUnit-CR-source surface reaches for exactly one typed
1997    /// dispatch — the resolver's accept-set migrates as a unit on any
1998    /// future axis addition.
1999    ///
2000    /// Fifth and final outer top-level [`Caixa`] `&[T]`-return slice-
2001    /// accessor — folds on the "outer [`Caixa`] `&[T]` slice"
2002    /// projection pattern [`Self::autores`] (b5d813f) opened,
2003    /// [`Self::etiquetas`] (78c7d3c) folded on, [`Self::bibliotecas`]
2004    /// (8a36c23) closed the universal-axis text-tag family of, and
2005    /// [`Self::exe`] (65d9527) opened the foreign-code-slot sub-family
2006    /// of. Closes the outer-`Caixa` foreign-code-slot `&[T]` sub-family
2007    /// — with `:bibliotecas`, `:exe`, and `:servicos` now each carrying
2008    /// a substrate-canonical slice accessor, the trio of code-surface
2009    /// list slots the [`Self::validate_code_paths`] per-slot dispatch
2010    /// tuple carries is complete on the typed dispatch surface (the
2011    /// internal `[(":bibliotecas", &self.bibliotecas, ..), (":exe",
2012    /// &self.exe, ..), (":servicos", &self.servicos, ..)]` per-slot
2013    /// dispatch tuple's homogeneous `&Vec<String>`-typed shape blocks a
2014    /// per-element accessor swap in isolation — a future companion lift
2015    /// promotes the tuple's element type to `&[String]` and threads the
2016    /// triple of typed dispatches through as a unit). Sibling in shape
2017    /// to the peer per-`:supervisor`
2018    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2019    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2020    /// (a6e18d7), per-`:membros`
2021    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2022    /// per-`:contratos`
2023    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2024    /// per-`:upgrade-from :instructions`
2025    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2026    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2027    /// typed-slot list axes, extended here to the outer top-level
2028    /// [`Caixa`] universal-axis surface. Returns `&[String]` (not
2029    /// `&Vec<String>`) because every downstream consumer of the
2030    /// ComputeUnit-CR-source list treats it as a read-only sequence —
2031    /// the slice-view is the narrowest borrow that supports every
2032    /// present + roadmapped consumer (`.iter()`, `.len()`,
2033    /// `.is_empty()`, `.first()`) without leaking the backing `Vec`'s
2034    /// grow/push/reserve surface no consumer of the typed view reaches
2035    /// for (the storage-side `Vec` remains reachable through the
2036    /// `pub servicos` field for the mutation-carrying serde round-trip
2037    /// and per-test fixture-mutation paths, and for the
2038    /// [`Self::validate_code_paths`] per-slot dispatch tuple whose
2039    /// homogeneous-element-type shape carries the raw field access
2040    /// until the trio-closure lift promotes the tuple as a unit).
2041    /// Named `servicos()` to match the storage field's name; the
2042    /// accessor's identity maps onto the canonical CAIXA-SDLC §I
2043    /// vocabulary the slot's docstring already carries.
2044    #[must_use]
2045    pub const fn servicos(&self) -> &[String] {
2046        self.servicos.as_slice()
2047    }
2048
2049    /// Substrate-canonical per-`Caixa` `:deps` universal-axis
2050    /// runtime-dependency-declaration-list slice-accessor every consumer
2051    /// of the top-level manifest's runtime-dep-graph axis keys off —
2052    /// returns the author-declared `:deps` list verbatim as a `&[Dep]`
2053    /// slice-view over the same backing buffer the raw
2054    /// `self.deps.as_slice()` field access borrows from. Empty-list-
2055    /// carrying (`:deps` is a default-empty axis every `defcaixa` form
2056    /// supplies with an empty `()` when unset; the [`Self::from_lisp`]
2057    /// derive folds an omitted `:deps` through `#[serde(default)]` to
2058    /// `Vec::new()`, so a `Caixa` past parse definitionally carries a
2059    /// `Vec<Dep>` slot — possibly empty — and the returned `&[Dep]`
2060    /// degenerates to an empty slice on that arm without any silent
2061    /// `None` collapse).
2062    ///
2063    /// The `:deps` slot carries the universal-axis runtime dependency
2064    /// list every kind of caixa emits under (CAIXA-SDLC §I — the author-
2065    /// facing surface every `defcaixa` form supplies alongside `:nome` /
2066    /// `:versao` / `:kind`; the substrate-wide runtime-closure-input axis
2067    /// every downstream resolver-facing artifact emits under) — the
2068    /// typed slot's `Vec<Dep>` accept-set (empty-`:nome` rejected through
2069    /// [`DepError::NomeEmpty`], non-DNS-1123-label `:nome` rejected
2070    /// through [`DepError::NomeInvalid`], malformed `:versao` rejected
2071    /// through [`DepError::VersaoInvalid`], empty `:fonte.repo` rejected
2072    /// through [`DepError::FonteRepoEmpty`], within-list duplicate `:nome`
2073    /// rejected through [`DepError::DuplicateNome { list: ":deps" }`])
2074    /// maps onto every load-bearing downstream consumer the substrate
2075    /// carries — the [`Self::validate_deps`] per-entry
2076    /// [`Dep::validate`] + within-list dedup walk at
2077    /// caixa-core/src/manifest.rs, the [`crate::dep::validate_no_self_dep`]
2078    /// cross-list self-reference gate at caixa-core/src/layout.rs that
2079    /// checks each entry against the caixa's own `:nome`, the
2080    /// caixa-resolver `for dep in &root.deps` closure walk at
2081    /// caixa-resolver/src/resolve.rs that seeds every git-clone target
2082    /// through the resolver's [`crate::Dep`]-keyed pipeline, the
2083    /// caixa-crd `caixa.deps.iter().map(dep_into_ref).collect()` fold at
2084    /// caixa-crd/src/conversion.rs that materializes each entry into the
2085    /// K8s `Caixa` CR's `spec.deps` field, every future per-`Caixa`
2086    /// resolver-facing renderer the CAIXA-SDLC §I roadmap acknowledges
2087    /// (the future per-cluster runtime-closure-audit overlay the M4 CR
2088    /// materializer resolves per-CR, the future `lacre.lisp` BLAKE3-
2089    /// closure emit walk the caixa-resolver docstring roadmaps).
2090    ///
2091    /// First outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2092    /// opens the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2093    /// sibling `:deps-dev` future lift closes on. Peer of the closed
2094    /// outer-`Caixa` foreign-code-slot `&[String]` sub-family
2095    /// ([`Self::bibliotecas`] 8a36c23, [`Self::exe`] 65d9527,
2096    /// [`Self::servicos`] 611f78b) and the outer-`Caixa` universal-axis
2097    /// text-tag family ([`Self::autores`] b5d813f, [`Self::etiquetas`]
2098    /// 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice" projection
2099    /// pattern onto a novel element-type axis (`Dep` composite vs the
2100    /// prior sibling family's `String` scalar). Sibling in shape to the
2101    /// peer per-`:supervisor`
2102    /// [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
2103    /// per-`:placement` [`crate::aplicacao::Placement::clusters`]
2104    /// (a6e18d7), per-`:membros`
2105    /// [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
2106    /// per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
2107    /// (0dcc926), and per-`:upgrade-from :instructions`
2108    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2109    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2110    /// typed-slot list axes, extended here to the outer top-level
2111    /// [`Caixa`] universal-axis dep-graph surface. Returns `&[Dep]`
2112    /// (not `&Vec<Dep>`) because every downstream consumer of the
2113    /// runtime-dep list treats it as a read-only sequence — the slice-
2114    /// view is the narrowest borrow that supports every present +
2115    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2116    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2117    /// of the typed view reaches for (the storage-side `Vec` remains
2118    /// reachable through the `pub deps` field for the mutation-carrying
2119    /// serde round-trip and per-test fixture-mutation paths). Named
2120    /// `deps()` to match the storage field's name; the accessor's
2121    /// identity maps onto the canonical CAIXA-SDLC §I vocabulary the
2122    /// slot's docstring already carries.
2123    #[must_use]
2124    pub const fn deps(&self) -> &[Dep] {
2125        self.deps.as_slice()
2126    }
2127
2128    /// Substrate-canonical per-`Caixa` `:deps-dev` universal-axis
2129    /// development-only-dependency-declaration-list slice-accessor every
2130    /// consumer of the top-level manifest's dev-dep-graph axis keys off —
2131    /// returns the author-declared `:deps-dev` list verbatim as a `&[Dep]`
2132    /// slice-view over the same backing buffer the raw
2133    /// `self.deps_dev.as_slice()` field access borrows from. Empty-list-
2134    /// carrying (`:deps-dev` is a default-empty axis every `defcaixa`
2135    /// form supplies with an empty `()` when unset; the
2136    /// [`Self::from_lisp`] derive folds an omitted `:deps-dev` through
2137    /// `#[serde(default)]` to `Vec::new()`, so a `Caixa` past parse
2138    /// definitionally carries a `Vec<Dep>` slot — possibly empty — and
2139    /// the returned `&[Dep]` degenerates to an empty slice on that arm
2140    /// without any silent `None` collapse).
2141    ///
2142    /// The `:deps-dev` slot carries the universal-axis dev-only
2143    /// dependency list every kind of caixa emits under (CAIXA-SDLC §I —
2144    /// the author-facing sibling of `:deps` that every `defcaixa` form
2145    /// supplies to declare tests / lint / bench closures the runtime
2146    /// `:deps` axis does not carry; the substrate-wide dev-closure-input
2147    /// axis every downstream test-facing artifact emits under, matching
2148    /// Cargo's `[dev-dependencies]` table's dev-time-only visibility
2149    /// contract) — the typed slot's `Vec<Dep>` accept-set (empty-`:nome`
2150    /// rejected through [`DepError::NomeEmpty`], non-DNS-1123-label
2151    /// `:nome` rejected through [`DepError::NomeInvalid`], malformed
2152    /// `:versao` rejected through [`DepError::VersaoInvalid`], empty
2153    /// `:fonte.repo` rejected through [`DepError::FonteRepoEmpty`],
2154    /// within-list duplicate `:nome` rejected through
2155    /// [`DepError::DuplicateNome { list: ":deps-dev" }`]) maps onto every
2156    /// load-bearing downstream consumer the substrate carries — the
2157    /// [`Self::validate_deps`] per-entry [`Dep::validate`] + within-list
2158    /// dedup walk at caixa-core/src/manifest.rs, the
2159    /// [`crate::dep::validate_no_self_dep`] cross-list self-reference
2160    /// gate at caixa-core/src/layout.rs that checks each entry against
2161    /// the caixa's own `:nome`, the caixa-resolver
2162    /// `for dep in &root.deps_dev` closure walk at
2163    /// caixa-resolver/src/resolve.rs that seeds every dev-only git-clone
2164    /// target through the resolver's [`crate::Dep`]-keyed pipeline, and
2165    /// every future per-`Caixa` resolver-facing renderer the CAIXA-SDLC
2166    /// §I roadmap acknowledges (the future per-cluster dev-closure-audit
2167    /// overlay the M4 CR materializer resolves per-CR, the future
2168    /// `lacre.lisp` BLAKE3-closure emit walk the caixa-resolver docstring
2169    /// roadmaps).
2170    ///
2171    /// Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor —
2172    /// closes the outer-`Caixa` dependency-slot `&[Dep]` sub-family the
2173    /// sibling [`Self::deps`] (ad34b4e) opened on. The two accessors
2174    /// jointly close the two-list dep-graph surface every downstream
2175    /// resolver-facing consumer keys off (runtime `:deps` +
2176    /// dev-only `:deps-dev`, the canonical Cargo-shaped dependency-table
2177    /// pair the [`Self::validate_deps`] gate already walks in canonical
2178    /// order). Peer of the closed outer-`Caixa` foreign-code-slot
2179    /// `&[String]` sub-family ([`Self::bibliotecas`] 8a36c23,
2180    /// [`Self::exe`] 65d9527, [`Self::servicos`] 611f78b) and the outer-
2181    /// `Caixa` universal-axis text-tag family ([`Self::autores`]
2182    /// b5d813f, [`Self::etiquetas`] 78c7d3c) — folds the "outer
2183    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
2184    /// dev-dep composite-element axis (`Dep` composite, matching the
2185    /// [`Self::deps`] element type). Sibling in shape to the peer
2186    /// per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
2187    /// (bc92bce), per-`:placement`
2188    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7),
2189    /// per-`:membros` [`crate::aplicacao::AplicacaoSpec::membros`]
2190    /// (6c77e36), per-`:contratos`
2191    /// [`crate::aplicacao::AplicacaoSpec::contratos`] (0dcc926), and
2192    /// per-`:upgrade-from :instructions`
2193    /// [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
2194    /// `&[T]`-return slice accessors on the sibling per-M2 / per-M3
2195    /// typed-slot list axes, folded here to the outer top-level
2196    /// [`Caixa`] universal-axis dev-dep-graph surface. Returns `&[Dep]`
2197    /// (not `&Vec<Dep>`) because every downstream consumer of the
2198    /// dev-dep list treats it as a read-only sequence — the slice-view
2199    /// is the narrowest borrow that supports every present +
2200    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`) without
2201    /// leaking the backing `Vec`'s grow/push/reserve surface no consumer
2202    /// of the typed view reaches for (the storage-side `Vec` remains
2203    /// reachable through the `pub deps_dev` field for the mutation-
2204    /// carrying serde round-trip and per-test fixture-mutation paths).
2205    /// Named `deps_dev()` to match the storage field's `snake_case` name;
2206    /// the kebab-case author-surface tag `:deps-dev` is the same axis
2207    /// after tatara-lisp's kebab↔snake fold and the accessor's identity
2208    /// maps onto the canonical CAIXA-SDLC §I vocabulary the slot's
2209    /// docstring already carries.
2210    #[must_use]
2211    pub const fn deps_dev(&self) -> &[Dep] {
2212        self.deps_dev.as_slice()
2213    }
2214
2215    /// Substrate-canonical per-[`Caixa`] typed-dispatch read accessor
2216    /// every consumer that walks one of the two dep-list axes keyed on a
2217    /// [`crate::dep::DepList`] discriminant reaches for — routes the
2218    /// `(list: DepList) -> &[Dep]` projection through one typed method on
2219    /// the substrate primitive rather than the prior open-coded
2220    /// `match list { Prod => caixa.deps(), Dev => caixa.deps_dev() }`
2221    /// inline dispatch every per-axis walker would otherwise carry.
2222    /// Returns the author-declared per-list `Vec<Dep>` verbatim as a
2223    /// `&[Dep]` slice-view over the same backing buffer the sibling
2224    /// [`Self::deps`] (`Prod`) / [`Self::deps_dev`] (`Dev`) per-slot
2225    /// accessors borrow from, preserving the empty-list-carrying invariant
2226    /// each per-slot accessor already establishes (`:deps` / `:deps-dev`
2227    /// are default-empty axes every `defcaixa` form supplies with an empty
2228    /// `()` when unset; the [`Self::from_lisp`] derive folds an omitted
2229    /// list through `#[serde(default)]` to `Vec::new()`, so both arms
2230    /// definitionally carry a `Vec<Dep>` slot — possibly empty — and the
2231    /// returned `&[Dep]` degenerates to an empty slice on either arm
2232    /// without any silent `None` collapse).
2233    ///
2234    /// The [`crate::dep::DepList`] closed-set typed enum is the
2235    /// substrate's canonical discriminator for the "runtime-closure
2236    /// `:deps` vs dev-only-closure `:deps-dev`" axis every dep-list
2237    /// consumer dispatches on — the compiler-checked exhaustiveness on
2238    /// the enum's `match` arms is the build-time guarantee that no future
2239    /// per-list read-site regresses to a bare-`bool`-flag inline dispatch
2240    /// that a future third dep-list axis (a `:deps-build` build-only
2241    /// closure once the substrate grows cross-artifact heterogeneous
2242    /// dep-graphs, per CAIXA-SDLC §I) would silently split at every
2243    /// consumer. Prior to this the read side carried two per-slot
2244    /// accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`]) and no
2245    /// typed dispatch that a per-axis walker could parametrise on, so
2246    /// every per-list walker (the [`Self::validate_deps`] per-list
2247    /// [`crate::render::insert_first_seen`] dedup walk, a future
2248    /// `feira app graph` per-list dep summary, a future M4 per-cluster
2249    /// dev-closure-audit overlay the CR materializer resolves per-CR)
2250    /// open-coded the same two-block "run over `:deps`, then run over
2251    /// `:deps-dev`" pattern — a silent duplication that a future third
2252    /// dep-list axis would have had to grow a third block at every site.
2253    ///
2254    /// Peer of the sibling [`Self::push_dep`] typed-mutation dispatch
2255    /// (359fba5) — closes the two-side dispatch symmetry on the outer
2256    /// [`Caixa`] two-list dep-graph surface: `push_dep` on the mutation
2257    /// side, `deps_of` on the read side, both keyed on the same
2258    /// [`crate::dep::DepList`] discriminator. Same "one typed dispatch on
2259    /// the substrate primitive, thin projections at each consumer"
2260    /// discipline the sibling per-slot read accessors ([`Self::nome`]
2261    /// e6b7d97, [`Self::versao`], [`Self::kind`]) carry — extended onto
2262    /// the outer-[`Caixa`] typed-dispatch read surface.
2263    ///
2264    /// Declared `pub const fn` — every operator in the body is already
2265    /// `const`-callable (the [`crate::dep::DepList`] enum is a plain
2266    /// closed-set `#[derive(Copy)]` discriminator so the `match` arms
2267    /// are const-evaluable, and each arm forwards through the sibling
2268    /// `pub const fn` [`Self::deps`] / [`Self::deps_dev`] per-slot
2269    /// slice accessor). Pinned load-bearing by the paired
2270    /// [`caixa_deps_of_is_const_fn`][pin] wrapper test (a
2271    /// `const fn deps_of_via_const_fn(c: &Caixa, l: DepList) -> &[Dep]`
2272    /// that forwards through this accessor) — any future accidental
2273    /// downgrade to non-`const` fails the wrapper at caixa-core build
2274    /// time with E0015 (`cannot call non-const method`), strictly
2275    /// stronger than a runtime `assert!` and side-stepping the
2276    /// destructor-in-const restriction the `Caixa` fixture's owning
2277    /// carriers rule out on the direct-`const _: () = assert!(…)`
2278    /// residence. Peer of the sibling per-`Dep` outer-accessor
2279    /// family's parallel `const`-eval-surface pass and of the outer-
2280    /// `Caixa` slice-return accessor family's earlier pass (231a968)
2281    /// — same "one canonical dispatch per axis, `const`-eval posture
2282    /// pinned at the substrate primitive, thin projections at each
2283    /// consumer" discipline extended onto the outer-`Caixa`
2284    /// typed-dispatch read surface on the [`DepList`]-keyed dep-list
2285    /// axis.
2286    ///
2287    /// [DepList]: crate::dep::DepList
2288    /// [pin]: tests::caixa_deps_of_is_const_fn
2289    #[must_use]
2290    pub const fn deps_of(&self, list: crate::dep::DepList) -> &[Dep] {
2291        match list {
2292            crate::dep::DepList::Prod => self.deps(),
2293            crate::dep::DepList::Dev => self.deps_dev(),
2294        }
2295    }
2296
2297    /// Substrate-canonical per-[`Caixa`] typed-mutation dispatch every
2298    /// consumer that appends to one of the two dep-list axes keys off
2299    /// — routes the `(list: DepList, dep: Dep)` tuple through one typed
2300    /// method on the substrate primitive rather than the prior
2301    /// `feira add`-side open-coded `if self.dev { &mut caixa.deps_dev }
2302    /// else { &mut caixa.deps }` inline dispatch + open-coded
2303    /// `.iter().any(|d| d.nome == …)` dup-check cascade. Refuses the
2304    /// mutation with the canonical typed [`DepError::DuplicateNome`] on
2305    /// a within-list name collision — the same `list: &'static str`
2306    /// diagnostic shape [`Self::validate_deps`]'s per-list
2307    /// [`crate::render::insert_first_seen`] walk raises on the peer
2308    /// parse-time within-list dedup axis, so a future author reading a
2309    /// `feira add` refusal and a `feira build` refusal reaches for the
2310    /// same corrective surface without switching diagnostic idioms.
2311    ///
2312    /// The two-arm [`crate::dep::DepList`] enum is the substrate's
2313    /// closed-set typed carrier for the "runtime-closure `:deps` vs
2314    /// dev-only-closure `:deps-dev`" axis every dep-list consumer
2315    /// dispatches on — the compiler-checked exhaustiveness on the
2316    /// enum's `match` arms is the build-time guarantee that no future
2317    /// per-list mutation-site regresses to a bare-`bool`-flag
2318    /// (`is_dev: bool`) inline dispatch that a future third
2319    /// dep-list axis (a `:deps-build` build-only closure once the
2320    /// substrate grows cross-artifact heterogeneous dep-graphs, per
2321    /// CAIXA-SDLC §I) would silently split at every consumer.
2322    ///
2323    /// Same "one typed dispatch on the substrate primitive, thin
2324    /// projections at each consumer" discipline the sibling per-slot
2325    /// read accessors ([`Self::deps`] ad34b4e, [`Self::deps_dev`],
2326    /// [`Self::nome`] e6b7d97, [`Self::versao`], [`Self::kind`])
2327    /// carry — extended onto the outer-[`Caixa`] typed-mutation surface,
2328    /// the substrate's first typed-mutation dispatch on the top-level
2329    /// manifest. The prior `feira add` open-coded `&mut caixa.deps` /
2330    /// `&mut caixa.deps_dev` inline field-access + `bail!` string-
2331    /// diagnostic path routed no through-line back to the typed slot,
2332    /// so a future extension of either dep-list axis to a richer author
2333    /// surface (a per-cluster override the operator pins through a
2334    /// future `:placement`-scoped dep-list slot the CAIXA-SDLC §I
2335    /// roadmap acknowledges, an M4
2336    /// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
2337    /// admission-webhook that normalized the list at admission time)
2338    /// would have had to be threaded through the `feira add` mutation
2339    /// site in lockstep with every read consumer or one path would
2340    /// silently disagree with the other on which list a given dep lands
2341    /// in. Lifting the resolution rule to a typed method on the
2342    /// substrate primitive means every downstream dep-list-mutating
2343    /// consumer of the top-level manifest reaches for exactly one typed
2344    /// dispatch — the resolver's accept-set migrates as a unit on any
2345    /// future axis addition.
2346    ///
2347    /// # Errors
2348    ///
2349    /// Returns [`DepError::DuplicateNome`] with `list = list.as_str()`
2350    /// when another entry in the same list already carries the same
2351    /// `:nome` — the mutation is refused and the caller can surface the
2352    /// typed diagnostic to the author (the `feira add` verb routes the
2353    /// error through `anyhow::Error::from`, which preserves the
2354    /// canonical `#[error(...)]`-templated diagnostic body).
2355    pub fn push_dep(&mut self, list: crate::dep::DepList, dep: Dep) -> Result<(), DepError> {
2356        let target = match list {
2357            crate::dep::DepList::Prod => &mut self.deps,
2358            crate::dep::DepList::Dev => &mut self.deps_dev,
2359        };
2360        if target.iter().any(|d| d.nome() == dep.nome()) {
2361            return Err(DepError::duplicate_nome(dep.nome(), list.as_str()));
2362        }
2363        target.push(dep);
2364        Ok(())
2365    }
2366
2367    /// Substrate-canonical per-`Caixa` `:limits` M2 typed-slot outer-
2368    /// composite Lunatic-per-process wasm32-sandboxing-composite optional-
2369    /// composite-reference accessor every consumer of the top-level
2370    /// manifest's per-Servico [`LimitsSpec`] outer-composite reader keys
2371    /// off — returns the author-declared `:limits` typed composite
2372    /// verbatim as an `Option<&LimitsSpec>` reference over the same
2373    /// backing storage the raw `self.limits.as_ref()` field access
2374    /// borrows from, with `None` naming the "no `:limits` block
2375    /// authored — every per-axis Lunatic-sandbox cap defers to the
2376    /// wasm-engine-default arm named on the per-axis
2377    /// [`LimitsSpec::memory`] / [`LimitsSpec::fuel`] /
2378    /// [`LimitsSpec::wall_clock`] / [`LimitsSpec::cpu`] scalar-accessor
2379    /// docstrings" partition every downstream Servico-M2-overlay
2380    /// emitter treats as "emit nothing" and the sibling
2381    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate
2382    /// treats as "skip the per-axis
2383    /// [`crate::LimitsError::MemoryZero`] / `MemoryBelowWasm32Page` /
2384    /// `FuelZero` / `WallClockZero` / `CpuZero` refusal cascade".
2385    ///
2386    /// The outer `:limits` slot carries the M2 Servico-runtime typed
2387    /// composite — the load-bearing container of every Lunatic-shaped
2388    /// per-process wasm32-sandbox cap axis every long-running wasm
2389    /// component's runtime dispatches on (INSPIRATIONS §III.1 —
2390    /// Lunatic per-process linear-memory / fuel / wall-clock /
2391    /// millicore cap primitives translated onto pleme-io's typed
2392    /// `:limits :memory` / `:limits :fuel` / `:limits :wall-clock` /
2393    /// `:limits :cpu` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2394    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2395    /// chart both fan on). Every per-`:limits` axis threads through a
2396    /// lifted per-slot accessor on the [`LimitsSpec`] type: the
2397    /// [`LimitsSpec::memory`] wasm32 linear-memory byte-cap scalar
2398    /// accessor, the [`LimitsSpec::fuel`] wasmtime fuel-cap scalar
2399    /// accessor, the [`LimitsSpec::wall_clock`] per-call wall-clock
2400    /// deadline scalar accessor, and the [`LimitsSpec::cpu`]
2401    /// K8s-millicore soft-CPU-share scalar accessor. Every downstream
2402    /// consumer that reaches for a limits axis first passes through
2403    /// this outer accessor onto the composite and then dispatches
2404    /// onto the per-axis accessor — the two-level dispatch means
2405    /// every per-`:limits` reader now routes through a typed dispatch
2406    /// on the substrate primitive at both altitudes.
2407    ///
2408    /// Prior to this lift the `.limits` `Option<LimitsSpec>` composite
2409    /// was accessed inline at three production sites — the
2410    /// [`crate::StandardLayout::verify`] per-`:limits` shape gate's
2411    /// `if let Some(l) = &caixa.limits { … }` traversal head
2412    /// (caixa-core/src/layout.rs:882, which drives the per-axis
2413    /// refusal cascade on the composite: the `LimitsError::MemoryZero`
2414    /// / `MemoryBelowWasm32Page` / `MemoryExceedsWasm32Max` /
2415    /// `FuelZero` / `FuelExceedsMax` / `WallClockZero` /
2416    /// `WallClockExceedsMax` / `CpuZero` / `CpuExceedsMax` refusals
2417    /// [`LimitsSpec::validate`] fans onto), the
2418    /// [`crate::render::servico_m2_overlay`] per-Servico M2 overlay
2419    /// emitter's `if let Some(limits) = &caixa.limits { … }` traversal
2420    /// head (caixa-core/src/render.rs:18504, which drives the
2421    /// `M2_KEY_LIMITS`-keyed `limits.is_empty()`-gated `serde_yaml`
2422    /// projection every `caixa-helm` / `caixa-flux` Servico values-
2423    /// block emitter fans on), and the
2424    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2425    /// set enumerator's `self.limits.is_some()` presence probe
2426    /// (caixa-core/src/manifest.rs:1788, which drives the
2427    /// `M2_AUTHOR_KEY_LIMITS` kebab-case author-label push every
2428    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2429    /// gate reads) — three open-coded outer-field accesses that
2430    /// expressed no compile-time link back to the typed slot at the
2431    /// [`Caixa`] altitude. A future extension of the `:limits` outer
2432    /// axis to a richer author surface (a multi-`:limits` list the M4
2433    /// CR materializer resolves per-CR at admission time so a Servico
2434    /// can expose a compute-heavy + IO-heavy limits pair, a per-
2435    /// cluster `:limits-overrides` slot the operator pins so a
2436    /// cluster-specific policy can tighten a caixa-declared cap
2437    /// without re-authoring the `caixa.lisp`, a promotion of the
2438    /// plain `Option<LimitsSpec>` to a richer
2439    /// `{static, dynamic}` partition once the wasm-engine's runtime-
2440    /// resolved dynamic-cap surface lands) would have had to be
2441    /// threaded through all three open-coded copies in lockstep or
2442    /// one consumer would silently disagree with the peers on which
2443    /// limits composite a given Caixa resolves to — the layout gate's
2444    /// per-axis bracket-dispatch seed reading the raw slot while the
2445    /// peer `servico_m2_overlay` emitter read an operator-resolved
2446    /// slot would silently split the build-time sandbox-shape gate
2447    /// from the runtime `ComputeUnit` CR emission gate, a three-
2448    /// consumer split at the layout gate, the M2 overlay emitter, and
2449    /// the declared-slot enumerator far from the source `caixa.lisp`
2450    /// with no field naming the limits-drift root cause. Lifting the
2451    /// resolution rule to a typed method on the substrate primitive
2452    /// means every downstream consumer of the caixa's per-`Caixa`
2453    /// Lunatic-sandboxing outer-composite surface reaches for exactly
2454    /// one typed dispatch — the resolver's accept-set migrates as a
2455    /// unit on any future axis addition.
2456    ///
2457    /// First outer top-level [`Caixa`] `Option<&Composite>`-return
2458    /// composite-reference accessor — opens the outer-`Caixa`
2459    /// `Option<&Composite>` composite-reference projection pattern the
2460    /// sibling per-`Caixa` `:behavior` [`crate::BehaviorSpec`] /
2461    /// `:politicas` [`crate::aplicacao::MeshPolicy`] / `:placement`
2462    /// [`crate::aplicacao::Placement`] / `:entrada`
2463    /// [`crate::aplicacao::Entrada`] future outer-composite lifts
2464    /// fold on. Peer of the M3 mesh-slot outer-composite family the
2465    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2466    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2467    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2468    /// accessors already close on the outer [`crate::AplicacaoSpec`]
2469    /// altitude — extends that "one typed dispatch on the substrate
2470    /// primitive, thin projections at each consumer" discipline onto
2471    /// the outer top-level [`Caixa`] altitude, opening the M2 Servico-
2472    /// runtime slot family's outer-composite axis. Returns
2473    /// `Option<&LimitsSpec>` (not the owning composite by copy or
2474    /// clone) because every downstream consumer of the limits
2475    /// composite treats it as a read-only per-axis dispatch source —
2476    /// the reference-view is the narrowest borrow that supports every
2477    /// present + roadmapped consumer (per-axis accessor dispatch,
2478    /// `.is_empty()`-gated overlay projection, presence-probe early
2479    /// return on the "author-omitted `:limits` ⇒ engine-default
2480    /// applies" partition) without cloning the composite through
2481    /// every consumer's fast path. The `Option` half of the return-
2482    /// type preserves the load-bearing "author-omitted `:limits` ⇒
2483    /// engine-default applies" partition (not a default composite the
2484    /// downstream must reject on emptiness) — the accessor projects
2485    /// the raw `Option<LimitsSpec>` slot's presence bit through the
2486    /// reference-return unchanged. Named `limits()` to match the
2487    /// storage field's name verbatim and the tatara-lisp author-
2488    /// surface term (`:limits`) the field's own docstring already
2489    /// carries.
2490    #[must_use]
2491    pub const fn limits(&self) -> Option<&LimitsSpec> {
2492        self.limits.as_ref()
2493    }
2494
2495    /// Substrate-canonical per-`Caixa` `:behavior` M2 typed-slot outer-
2496    /// composite OTP-`gen_server`-shaped callback-table optional-
2497    /// composite-reference accessor every consumer of the top-level
2498    /// manifest's per-Servico [`BehaviorSpec`] outer-composite reader
2499    /// keys off — returns the author-declared `:behavior` typed
2500    /// composite verbatim as an `Option<&BehaviorSpec>` reference over
2501    /// the same backing storage the raw `self.behavior.as_ref()` field
2502    /// access borrows from, with `None` naming the "no `:behavior`
2503    /// block authored — every per-callback OTP-shaped hook defers to
2504    /// the wasm-engine's runtime default arm named on the per-axis
2505    /// [`BehaviorSpec::on_init`] / [`BehaviorSpec::on_call`] /
2506    /// [`BehaviorSpec::on_cast`] / [`BehaviorSpec::on_info`] /
2507    /// [`BehaviorSpec::on_state_change`] /
2508    /// [`BehaviorSpec::on_terminate`] scalar-accessor docstrings"
2509    /// partition every downstream Servico-M2-overlay emitter treats as
2510    /// "emit nothing" and the sibling [`crate::StandardLayout::verify`]
2511    /// per-`:behavior` shape gate treats as "skip the per-arm
2512    /// [`crate::behavior::BehaviorError`] refusal cascade + the
2513    /// per-callback on-disk `MissingEntry` existence check".
2514    ///
2515    /// The outer `:behavior` slot carries the M2 Servico-runtime typed
2516    /// composite — the load-bearing container of every OTP-shaped
2517    /// per-Servico lifecycle-callback path axis every long-running wasm
2518    /// component's runtime dispatches on (INSPIRATIONS §II.3 — Erlang/
2519    /// OTP `gen_server:init/1` / `handle_call/3` / `handle_cast/2` /
2520    /// `handle_info/2` / `code_change/3` / `terminate/2` primitives
2521    /// translated onto pleme-io's typed `:behavior :on-init` /
2522    /// `:on-call` / `:on-cast` / `:on-info` / `:on-state-change` /
2523    /// `:on-terminate` sub-slot axes; CAIXA-SDLC §II — the typed-M2
2524    /// slot algebra the wasm-engine + `pleme-computeunit` Helm-library
2525    /// chart both fan on). Every per-`:behavior` axis threads through a
2526    /// lifted per-callback accessor on the [`BehaviorSpec`] type
2527    /// (9b4ecde / d66c702 / 156ddbe / 99616ac / 4846cef / 701add7).
2528    /// Every downstream consumer that reaches for a behavior axis
2529    /// first passes through this outer accessor onto the composite
2530    /// and then dispatches onto the per-callback accessor — the
2531    /// two-level dispatch means every per-`:behavior` reader now
2532    /// routes through a typed dispatch on the substrate primitive at
2533    /// both altitudes.
2534    ///
2535    /// Composes cross-slot with the M2 `:upgrade-from` gate: the
2536    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
2537    /// cross-slot composition gate at [`crate::StandardLayout::verify`]
2538    /// keys the "per-version `:state-change` instruction must have a
2539    /// `:on-state-change` callback" precondition off this accessor's
2540    /// composite (the callback-side counterpart to the
2541    /// `:upgrade-from :instructions :state-change :script` refusal at
2542    /// the appup-side). Threading that gate's traversal input through
2543    /// this accessor closes the cross-slot invariant on the substrate
2544    /// primitive, not on the raw field.
2545    ///
2546    /// Prior to this lift the `.behavior` `Option<BehaviorSpec>`
2547    /// composite was accessed inline at four production sites — the
2548    /// [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
2549    /// `if let Some(b) = &caixa.behavior { … }` traversal head
2550    /// (caixa-core/src/layout.rs:896, which drives the per-arm
2551    /// `BehaviorError` refusal cascade + the per-callback on-disk
2552    /// [`crate::LayoutError::MissingEntry`] existence check under
2553    /// [`crate::render::LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`]),
2554    /// the [`crate::upgrade::validate_upgrade_from_against_behavior`]
2555    /// cross-slot composition gate's `caixa.behavior.as_ref()`
2556    /// traversal-input feed (caixa-core/src/layout.rs:1008, which
2557    /// drives the `:state-change` ↔ `:on-state-change` precondition
2558    /// refusal), the [`crate::render::servico_m2_overlay`] per-Servico
2559    /// M2 overlay emitter's `if let Some(behavior) = &caixa.behavior
2560    /// { … }` traversal head (caixa-core/src/render.rs:18513, which
2561    /// drives the `M2_KEY_BEHAVIOR`-keyed `behavior.is_empty()`-gated
2562    /// `serde_yaml` projection every `caixa-helm` / `caixa-flux`
2563    /// Servico values-block emitter fans on), and the
2564    /// [`Self::declared_servico_slots`] per-Servico M2 declared-slot-
2565    /// set enumerator's `self.behavior.is_some()` presence probe
2566    /// (caixa-core/src/manifest.rs:1919, which drives the
2567    /// `M2_AUTHOR_KEY_BEHAVIOR` kebab-case author-label push every
2568    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
2569    /// gate reads) — four open-coded outer-field accesses that
2570    /// expressed no compile-time link back to the typed slot at the
2571    /// [`Caixa`] altitude. A future extension of the `:behavior`
2572    /// outer axis to a richer author surface (a per-callback overlay
2573    /// resolver the operator materializes at admission time so a
2574    /// cluster-specific policy can inject a per-callback tracing
2575    /// interceptor without re-authoring the `caixa.lisp`, a promotion
2576    /// of the plain `Option<BehaviorSpec>` to a richer `{static,
2577    /// dynamic}` partition once a runtime-resolved behavior-swap
2578    /// surface lands, the M4 per-callback middleware chain the
2579    /// caixa-operator's per-Servico admission webhook keys off) would
2580    /// have had to be threaded through all four open-coded copies in
2581    /// lockstep or one consumer would silently disagree with the
2582    /// peers on which behavior composite a given Caixa resolves to —
2583    /// the layout gate's per-callback existence-check seed reading
2584    /// the raw slot while the peer `servico_m2_overlay` emitter read
2585    /// an operator-resolved slot would silently split the build-time
2586    /// callback-shape gate from the runtime `ComputeUnit` CR emission
2587    /// gate from the cross-slot `:state-change` composition gate from
2588    /// the M2 declared-slot enumerator, a four-consumer split far
2589    /// from the source `caixa.lisp` with no field naming the
2590    /// behavior-drift root cause. Lifting the resolution rule to a
2591    /// typed method on the substrate primitive means every downstream
2592    /// consumer of the caixa's per-`Caixa` OTP-callback-table outer-
2593    /// composite surface reaches for exactly one typed dispatch — the
2594    /// resolver's accept-set migrates as a unit on any future axis
2595    /// addition.
2596    ///
2597    /// Second outer top-level [`Caixa`] `Option<&Composite>`-return
2598    /// composite-reference accessor — sibling to the opening
2599    /// [`Self::limits`] (b2bd9d7) accessor on the outer-`Caixa`
2600    /// `Option<&Composite>` composite-reference sub-family, extends
2601    /// the "one typed dispatch on the substrate primitive, thin
2602    /// projections at each consumer" discipline onto the second of
2603    /// the three M2 Servico-runtime slots. The remaining
2604    /// `Option<&Composite>` axes at the outer top-level [`Caixa`]
2605    /// altitude — the M3 mesh-slot family (`:politicas`,
2606    /// `:placement`, `:entrada` — already closed on the inner
2607    /// [`crate::AplicacaoSpec`] altitude via 534dc21 / 9abb8f0 /
2608    /// d32111c) — remain the future sibling lifts on the outer
2609    /// top-level projection. Returns `Option<&BehaviorSpec>` (not
2610    /// the owning composite by copy or clone) because every
2611    /// downstream consumer of the behavior composite treats it as a
2612    /// read-only per-callback dispatch source — the reference-view is
2613    /// the narrowest borrow that supports every present + roadmapped
2614    /// consumer (per-callback accessor dispatch, `.is_empty()`-gated
2615    /// overlay projection, presence-probe early return on the
2616    /// "author-omitted `:behavior` ⇒ runtime-default applies"
2617    /// partition, cross-slot `:state-change` composition input)
2618    /// without cloning the composite through every consumer's fast
2619    /// path. The `Option` half of the return-type preserves the
2620    /// load-bearing "author-omitted `:behavior` ⇒ runtime-default
2621    /// applies" partition (not a default composite the downstream
2622    /// must reject on emptiness) — the accessor projects the raw
2623    /// `Option<BehaviorSpec>` slot's presence bit through the
2624    /// reference-return unchanged. Named `behavior()` to match the
2625    /// storage field's name verbatim and the tatara-lisp author-
2626    /// surface term (`:behavior`) the field's own docstring already
2627    /// carries.
2628    #[must_use]
2629    pub const fn behavior(&self) -> Option<&crate::BehaviorSpec> {
2630        self.behavior.as_ref()
2631    }
2632
2633    /// Substrate-canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
2634    /// composite MESH-COMPOSITION-shaped mesh-policy optional-composite-
2635    /// reference accessor every consumer of the top-level manifest's
2636    /// per-Aplicacao [`crate::aplicacao::MeshPolicy`] outer-composite
2637    /// reader keys off — returns the author-declared `:politicas` typed
2638    /// composite verbatim as an `Option<&MeshPolicy>` reference over the
2639    /// same backing storage the raw `self.politicas.as_ref()` field
2640    /// access borrows from, with `None` naming the "no `:politicas`
2641    /// block authored — every per-axis mesh-policy scalar defers to the
2642    /// cluster-default arm named on the per-axis
2643    /// [`crate::aplicacao::MeshPolicy::timeout`] /
2644    /// [`crate::aplicacao::MeshPolicy::retries`] /
2645    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] /
2646    /// [`crate::aplicacao::MeshPolicy::mtls_required`] /
2647    /// [`crate::aplicacao::MeshPolicy::rate_limit`] scalar-accessor
2648    /// docstrings" partition every downstream caixa-mesh /
2649    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2650    /// "emit no per-`:politicas` overlay" and the sibling
2651    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2652    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2653    /// arm.
2654    ///
2655    /// The outer `:politicas` slot carries the M3 mesh-slot per-
2656    /// Aplicacao typed composite — the load-bearing container of every
2657    /// mesh-level policy axis every Cilium NetworkPolicy / Gateway API
2658    /// v1.x HTTPRoute / future M4 per-edge policy overlay emitter fans
2659    /// on (MESH-COMPOSITION §III.2 — the Aplicacao's typed mesh-policy
2660    /// composite; §V — the "no infinite blocking" per-call deadline +
2661    /// "sandboxing-by-default" mTLS-enforcement CSE invariants; §III.3
2662    /// — the typed inter-Servico contrato-edge overlay the per-`(:de,
2663    /// :para)` mesh renderer keys off). Every per-`:politicas` axis
2664    /// threads through a lifted per-slot accessor on the
2665    /// [`crate::aplicacao::MeshPolicy`] type: the
2666    /// [`crate::aplicacao::MeshPolicy::mtls_required`] (c0110f1) Cilium
2667    /// mTLS-enforcement toggle, the
2668    /// [`crate::aplicacao::MeshPolicy::retries`] (bdfb399) transient-
2669    /// failure retry budget, the [`crate::aplicacao::MeshPolicy::timeout`]
2670    /// (7073d0f) Gateway-API per-call deadline, the
2671    /// [`crate::aplicacao::MeshPolicy::circuit_breaker`] (b0e741a)
2672    /// Envoy-outlier-detection composite. Every downstream consumer
2673    /// that reaches for a mesh-policy axis first passes through this
2674    /// outer accessor onto the composite and then dispatches onto the
2675    /// per-axis accessor — the two-level dispatch means every per-
2676    /// `:politicas` reader now routes through a typed dispatch on the
2677    /// substrate primitive at both altitudes.
2678    ///
2679    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2680    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2681    /// author-omitted arm onto the [`crate::aplicacao::MeshPolicy::default`]
2682    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::politicas`]
2683    /// (534dc21) `&MeshPolicy`-return accessor observes a typed
2684    /// composite whether or not the author declared the outer slot.
2685    /// The outer accessor preserves the "author-omitted vs authored-
2686    /// empty" partition the inner accessor's `is_empty()`-gated
2687    /// renderer overlay collapses — routing the presence bit through
2688    /// this accessor keeps the [`Self::declared_mesh_slots`] M3 kind-
2689    /// coherence enumerator's `M3_AUTHOR_KEY_POLITICAS` push separate
2690    /// from the inner `MeshPolicy::is_empty()`-gated overlay elision.
2691    ///
2692    /// Prior to this lift the `.politicas` `Option<MeshPolicy>`
2693    /// composite was accessed inline at two production sites — the
2694    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2695    /// `self.politicas.clone().unwrap_or_default()` traversal head
2696    /// (caixa-core/src/manifest.rs:1899, which drives the fold onto
2697    /// the [`crate::aplicacao::MeshPolicy::default`] cluster-default
2698    /// arm the inner [`crate::AplicacaoSpec::politicas`] accessor
2699    /// then observes), and the [`Self::declared_mesh_slots`] M3
2700    /// declared-slot-set enumerator's `self.politicas.is_some()`
2701    /// presence probe (caixa-core/src/manifest.rs:1961, which drives
2702    /// the `M3_AUTHOR_KEY_POLITICAS` kebab-case author-label push
2703    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2704    /// coherence gate reads) — two open-coded outer-field accesses
2705    /// that expressed no compile-time link back to the typed slot at
2706    /// the [`Caixa`] altitude. A future extension of the `:politicas`
2707    /// outer axis to a richer author surface (a per-cluster
2708    /// `:politicas-overrides` slot the operator materializes at
2709    /// admission time so a cluster-specific policy can tighten the
2710    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2711    /// promotion of the plain `Option<MeshPolicy>` to a richer
2712    /// `{static, dynamic}` partition once the M4 per-edge
2713    /// contrato-scoped policy-override surface lands, the M5 traffic-
2714    /// shaping composition the caixa-operator's per-Aplicacao mesh
2715    /// admission webhook keys off) would have had to be threaded
2716    /// through both open-coded copies in lockstep or the Aplicacao-
2717    /// composition seed's default-fold arm would silently disagree
2718    /// with the M3 declared-slot enumerator on which policy composite
2719    /// a given Caixa resolves to — the seed reading an operator-
2720    /// resolved slot while the enumerator's presence probe read the
2721    /// raw slot would silently split the build-time mesh-artifact
2722    /// emission gate from the M3 declared-slot enumerator's kind-
2723    /// coherence gate, a two-consumer split far from the source
2724    /// `caixa.lisp` with no field naming the policy-drift root cause.
2725    /// Lifting the resolution rule to a typed method on the substrate
2726    /// primitive means every downstream consumer of the caixa's per-
2727    /// `Caixa` MESH-COMPOSITION mesh-policy outer-composite surface
2728    /// reaches for exactly one typed dispatch — the resolver's
2729    /// accept-set migrates as a unit on any future axis addition.
2730    ///
2731    /// Third outer top-level [`Caixa`] `Option<&Composite>`-return
2732    /// composite-reference accessor — sibling to the opening
2733    /// [`Self::limits`] (b2bd9d7) and [`Self::behavior`] (35d8b52)
2734    /// accessors on the outer-`Caixa` `Option<&Composite>` composite-
2735    /// reference sub-family, extends the "one typed dispatch on the
2736    /// substrate primitive, thin projections at each consumer"
2737    /// discipline onto the first of the three M3 mesh-slot axes.
2738    /// Peer of the closed inner mesh-slot outer-composite family the
2739    /// sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
2740    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2741    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2742    /// accessor pins already close on the inner [`crate::AplicacaoSpec`]
2743    /// altitude — opens the outer top-level [`Caixa`] altitude's M3
2744    /// mesh-slot arm of the composite-reference family the remaining
2745    /// two axes (`:placement`, `:entrada`) fold onto in future
2746    /// sibling lifts. Returns `Option<&MeshPolicy>` (not the owning
2747    /// composite by copy or clone) because every downstream consumer
2748    /// of the mesh-policy composite treats it as a read-only per-axis
2749    /// dispatch source — the reference-view is the narrowest borrow
2750    /// that supports every present + roadmapped consumer (per-axis
2751    /// accessor dispatch, `.is_empty()`-gated overlay projection,
2752    /// presence-probe early return on the "author-omitted `:politicas`
2753    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2754    /// seed's default-fold arm) without cloning the composite through
2755    /// every consumer's fast path. The `Option` half of the return-
2756    /// type preserves the load-bearing "author-omitted `:politicas` ⇒
2757    /// cluster-default applies" partition (not a default composite
2758    /// the downstream must reject on emptiness) — the accessor
2759    /// projects the raw `Option<MeshPolicy>` slot's presence bit
2760    /// through the reference-return unchanged. Named `politicas()` to
2761    /// match the storage field's name verbatim and the tatara-lisp
2762    /// author-surface term (`:politicas`) the field's own docstring
2763    /// already carries.
2764    #[must_use]
2765    pub const fn politicas(&self) -> Option<&crate::aplicacao::MeshPolicy> {
2766        self.politicas.as_ref()
2767    }
2768
2769    /// Substrate-canonical per-`Caixa` `:placement` M3 mesh-slot outer-
2770    /// composite MESH-COMPOSITION-shaped distribution optional-composite-
2771    /// reference accessor every consumer of the top-level manifest's
2772    /// per-Aplicacao [`crate::aplicacao::Placement`] outer-composite
2773    /// reader keys off — returns the author-declared `:placement` typed
2774    /// composite verbatim as an `Option<&Placement>` reference over the
2775    /// same backing storage the raw `self.placement.as_ref()` field
2776    /// access borrows from, with `None` naming the "no `:placement`
2777    /// block authored — every per-axis placement scalar defers to the
2778    /// cluster-default arm named on the per-axis
2779    /// [`crate::aplicacao::Placement::estrategia`] /
2780    /// [`crate::aplicacao::Placement::clusters`] /
2781    /// [`crate::aplicacao::Placement::affinity`] /
2782    /// [`crate::aplicacao::Placement::shard_key`] scalar-accessor
2783    /// docstrings" partition every downstream caixa-mesh /
2784    /// caixa-flux / caixa-helm Aplicacao-artifact emitter treats as
2785    /// "emit no per-`:placement` overlay" and the sibling
2786    /// [`Self::aplicacao_view`] Aplicacao-composition seed folds through
2787    /// the [`crate::aplicacao::Placement::default`] cluster-default arm.
2788    ///
2789    /// The outer `:placement` slot carries the M3 mesh-slot per-
2790    /// Aplicacao typed distribution composite — the load-bearing
2791    /// container of every where-does-this-Aplicacao-run axis every
2792    /// caixa-mesh programs.yaml per-cluster distribution overlay /
2793    /// caixa-flux per-Aplicacao GitRepository/HelmRelease fan-out /
2794    /// future M4 per-Aplicacao Akka-style cluster-sharding entity-id
2795    /// resolver emitter fans on (MESH-COMPOSITION §II.4 — the
2796    /// Aplicacao's typed distribution composite; §V CSE invariants —
2797    /// "distribution is a first-class typed composite, not a runtime
2798    /// scheduler hint" the per-axis scalars enforce; §III.3 — the
2799    /// typed inter-Servico contrato-edge overlay the per-cluster
2800    /// mesh renderer keys off). Every per-`:placement` axis threads
2801    /// through a lifted per-slot accessor on the
2802    /// [`crate::aplicacao::Placement`] type: the
2803    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
2804    /// MESH-COMPOSITION distribution-strategy scalar, the
2805    /// [`crate::aplicacao::Placement::clusters`] (a6e18d7) per-cluster
2806    /// distribution-target slice, the [`crate::aplicacao::Placement::affinity`]
2807    /// M3-Adaptive-compression-hint optional-scalar, and the
2808    /// [`crate::aplicacao::Placement::shard_key`] (7cd2a28) Akka-cluster-
2809    /// sharding extractor-expression optional-scalar. Every downstream
2810    /// consumer that reaches for a placement axis first passes through
2811    /// this outer accessor onto the composite and then dispatches onto
2812    /// the per-axis accessor — the two-level dispatch means every per-
2813    /// `:placement` reader now routes through a typed dispatch on the
2814    /// substrate primitive at both altitudes.
2815    ///
2816    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2817    /// seed: the Aplicacao-view builder folds the outer `Option`'s
2818    /// author-omitted arm onto the [`crate::aplicacao::Placement::default`]
2819    /// cluster-default, so the peer inner [`crate::AplicacaoSpec::placement`]
2820    /// (9abb8f0) `&Placement`-return accessor observes a typed composite
2821    /// whether or not the author declared the outer slot. The outer
2822    /// accessor preserves the "author-omitted vs authored-empty" partition
2823    /// the inner accessor collapses at the cluster-default fold —
2824    /// routing the presence bit through this accessor keeps the
2825    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2826    /// `M3_AUTHOR_KEY_PLACEMENT` push separate from the inner
2827    /// [`crate::AplicacaoSpec::validate_placement`]-gated overlay
2828    /// dispatch.
2829    ///
2830    /// Prior to this lift the `.placement` `Option<Placement>`
2831    /// composite was accessed inline at two production sites — the
2832    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2833    /// `self.placement.clone().unwrap_or_default()` traversal head
2834    /// (caixa-core/src/manifest.rs:2036, which drives the fold onto
2835    /// the [`crate::aplicacao::Placement::default`] cluster-default
2836    /// arm the inner [`crate::AplicacaoSpec::placement`] accessor
2837    /// then observes), and the [`Self::declared_mesh_slots`] M3
2838    /// declared-slot-set enumerator's `self.placement.is_some()`
2839    /// presence probe (caixa-core/src/manifest.rs:2100, which drives
2840    /// the `M3_AUTHOR_KEY_PLACEMENT` kebab-case author-label push
2841    /// every [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
2842    /// coherence gate reads) — two open-coded outer-field accesses
2843    /// that expressed no compile-time link back to the typed slot at
2844    /// the [`Caixa`] altitude. A future extension of the `:placement`
2845    /// outer axis to a richer author surface (a per-cluster
2846    /// `:placement-overrides` slot the operator materializes at
2847    /// admission time so a cluster-specific placement can tighten the
2848    /// caixa-declared bound without re-authoring the `caixa.lisp`, a
2849    /// per-tenant placement-alias table the M4
2850    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer resolves
2851    /// per-CR at admission time, a promotion of the plain
2852    /// `Option<Placement>` to a richer `{static, dynamic}` partition
2853    /// once Orleans-style virtual-actor dynamic placement comes into
2854    /// typed scope) would have had to be threaded through both open-
2855    /// coded copies in lockstep or the Aplicacao-composition seed's
2856    /// default-fold arm would silently disagree with the M3 declared-
2857    /// slot enumerator on which distribution composite a given Caixa
2858    /// resolves to — the seed reading an operator-resolved slot while
2859    /// the enumerator's presence probe read the raw slot would
2860    /// silently split the build-time distribution-artifact emission
2861    /// gate from the M3 declared-slot enumerator's kind-coherence
2862    /// gate, a two-consumer split far from the source `caixa.lisp`
2863    /// with no field naming the distribution-drift root cause.
2864    /// Lifting the resolution rule to a typed method on the substrate
2865    /// primitive means every downstream consumer of the caixa's per-
2866    /// `Caixa` MESH-COMPOSITION distribution outer-composite surface
2867    /// reaches for exactly one typed dispatch — the resolver's
2868    /// accept-set migrates as a unit on any future axis addition.
2869    ///
2870    /// Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
2871    /// composite-reference accessor — sibling to the opening
2872    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) M2-
2873    /// Servico-runtime pair and the peer [`Self::politicas`] (5d23d29)
2874    /// M3-mesh-slot arm on the outer-`Caixa` `Option<&Composite>`
2875    /// composite-reference sub-family, folds on the "one typed
2876    /// dispatch on the substrate primitive, thin projections at each
2877    /// consumer" discipline extended onto the second of the three M3
2878    /// mesh-slot axes. Peer of the closed inner mesh-slot outer-
2879    /// composite family the sibling
2880    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
2881    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
2882    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
2883    /// accessor pins already close on the inner
2884    /// [`crate::AplicacaoSpec`] altitude — folds on the outer top-
2885    /// level [`Caixa`] altitude's M3 mesh-slot arm the sibling
2886    /// [`Self::politicas`] opened, extending the discipline onto the
2887    /// second of the three M3 mesh-slot axes. The remaining M3
2888    /// mesh-slot axis (`:entrada`) folds onto this accessor's
2889    /// discipline in the final sibling lift, closing the outer top-
2890    /// level [`Caixa`] `Option<&Composite>` M3 mesh-slot sub-family.
2891    /// Returns `Option<&Placement>` (not the owning composite by copy
2892    /// or clone) because every downstream consumer of the placement
2893    /// composite treats it as a read-only per-axis dispatch source —
2894    /// the reference-view is the narrowest borrow that supports every
2895    /// present + roadmapped consumer (per-axis accessor dispatch,
2896    /// serde composite-serialization on the programs.yaml overlay,
2897    /// presence-probe early return on the "author-omitted `:placement`
2898    /// ⇒ cluster-default applies" partition, `Aplicacao`-composition
2899    /// seed's default-fold arm) without cloning the composite through
2900    /// every consumer's fast path. The `Option` half of the return-
2901    /// type preserves the load-bearing "author-omitted `:placement` ⇒
2902    /// cluster-default applies" partition (not a default composite
2903    /// the downstream must reject on emptiness) — the accessor
2904    /// projects the raw `Option<Placement>` slot's presence bit
2905    /// through the reference-return unchanged. Named `placement()` to
2906    /// match the storage field's name verbatim and the tatara-lisp
2907    /// author-surface term (`:placement`) the field's own docstring
2908    /// already carries.
2909    #[must_use]
2910    pub const fn placement(&self) -> Option<&crate::aplicacao::Placement> {
2911        self.placement.as_ref()
2912    }
2913
2914    /// Substrate-canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
2915    /// composite MESH-COMPOSITION-shaped external-gateway optional-
2916    /// composite-reference accessor every consumer of the top-level
2917    /// manifest's per-Aplicacao [`crate::aplicacao::Entrada`] outer-
2918    /// composite reader keys off — returns the author-declared
2919    /// `:entrada` typed composite verbatim as an `Option<&Entrada>`
2920    /// reference over the same backing storage the raw
2921    /// `self.entrada.as_ref()` field access borrows from, with `None`
2922    /// naming the "no `:entrada` block authored — this Aplicacao is
2923    /// cluster-internal, no `Gateway`/`HTTPRoute` fan-out emitted"
2924    /// partition every downstream caixa-mesh Gateway-API artifact
2925    /// emitter treats as "emit no gateway-listener + no `HTTPRoute`
2926    /// backend for this Aplicacao" and the sibling
2927    /// [`Self::aplicacao_view`] Aplicacao-composition seed forwards
2928    /// verbatim (unlike the peer `:politicas` / `:placement` arms,
2929    /// `:entrada` has no cluster-default fold — an omitted `:entrada`
2930    /// stays `None` on the projected [`crate::AplicacaoSpec`] and the
2931    /// peer inner [`crate::AplicacaoSpec::entrada`] accessor observes
2932    /// the same `Option<&Entrada>` presence bit unchanged).
2933    ///
2934    /// The outer `:entrada` slot carries the M3 mesh-slot per-
2935    /// Aplicacao typed external-gateway composite — the load-bearing
2936    /// container of every how-does-the-outside-world-reach-this-
2937    /// Aplicacao axis every caixa-mesh `Gateway`/`HTTPRoute` fan-out
2938    /// emitter fans on (MESH-COMPOSITION §II.5 — the Aplicacao's typed
2939    /// external-entry composite; §V CSE invariants — "the external
2940    /// gateway is a first-class typed composite, not a per-Servico
2941    /// ingress annotation" the per-axis scalars enforce; §III.4 — the
2942    /// typed hostname + backend-Servico pair the per-cluster Gateway-
2943    /// API renderer keys off). Every per-`:entrada` axis threads
2944    /// through a lifted per-slot accessor on the
2945    /// [`crate::aplicacao::Entrada`] type: the
2946    /// [`crate::aplicacao::Entrada::host`] Gateway-API `Listener.hostname`
2947    /// scalar, the [`crate::aplicacao::Entrada::para`] backend-Servico
2948    /// caixa-name scalar, the [`crate::aplicacao::Entrada::paths`]
2949    /// per-rule `HTTPPathMatch` list, the [`crate::aplicacao::Entrada::port`]
2950    /// backend `trigger.service.port` scalar, and the
2951    /// [`crate::aplicacao::Entrada::resolved_paths`] URL-path fallback
2952    /// resolver every HTTPRoute-aware renderer consumes. Every
2953    /// downstream consumer that reaches for an entry axis first passes
2954    /// through this outer accessor onto the composite and then
2955    /// dispatches onto the per-axis accessor — the two-level dispatch
2956    /// means every per-`:entrada` reader now routes through a typed
2957    /// dispatch on the substrate primitive at both altitudes.
2958    ///
2959    /// Composes through [`Self::aplicacao_view`]'s Aplicacao-composition
2960    /// seed: the Aplicacao-view builder forwards the outer `Option`
2961    /// arm verbatim (no default fold — `:entrada` is inherently
2962    /// optional; a cluster-internal Aplicacao has no external gateway
2963    /// at all, not "an external gateway that defaults to nothing"), so
2964    /// the peer inner [`crate::AplicacaoSpec::entrada`] (d32111c)
2965    /// `Option<&Entrada>`-return accessor observes the same presence
2966    /// bit whether or not the author declared the outer slot. Routing
2967    /// the presence bit through this accessor keeps the
2968    /// [`Self::declared_mesh_slots`] M3 kind-coherence enumerator's
2969    /// `M3_AUTHOR_KEY_ENTRADA` push separate from the inner
2970    /// [`crate::AplicacaoSpec::validate_entrada`]-gated
2971    /// hostname/backend/path emission dispatch.
2972    ///
2973    /// Prior to this lift the `.entrada` `Option<Entrada>` composite
2974    /// was accessed inline at two production sites — the
2975    /// [`Self::aplicacao_view`] Aplicacao-composition seed's
2976    /// `self.entrada.clone()` traversal head (caixa-core/src/manifest.rs:2182,
2977    /// which drives the forward onto the peer inner
2978    /// [`crate::AplicacaoSpec::entrada`] accessor the caixa-mesh
2979    /// Gateway-API fan-out then observes), and the
2980    /// [`Self::declared_mesh_slots`] M3 declared-slot-set enumerator's
2981    /// `self.entrada.is_some()` presence probe (caixa-core/src/manifest.rs:2248,
2982    /// which drives the `M3_AUTHOR_KEY_ENTRADA` kebab-case author-
2983    /// label push every [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
2984    /// kind-coherence gate reads) — two open-coded outer-field
2985    /// accesses that expressed no compile-time link back to the typed
2986    /// slot at the [`Caixa`] altitude. A future extension of the
2987    /// `:entrada` outer axis to a richer author surface (a per-cluster
2988    /// `:entrada-overrides` slot the operator materializes at admission
2989    /// time so a cluster-specific hostname can pin the caixa-declared
2990    /// bound without re-authoring the `caixa.lisp`, a per-tenant
2991    /// gateway-alias table the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
2992    /// CR materializer resolves per-CR at admission time, a promotion
2993    /// of the plain `Option<Entrada>` to a richer
2994    /// `{public, private, internal}` partition once Cilium-identity-
2995    /// scoped internal gateways come into typed scope) would have had
2996    /// to be threaded through both open-coded copies in lockstep or the
2997    /// Aplicacao-composition seed's forward arm would silently
2998    /// disagree with the M3 declared-slot enumerator on which external-
2999    /// gateway composite a given Caixa resolves to — the seed reading
3000    /// an operator-resolved slot while the enumerator's presence probe
3001    /// read the raw slot would silently split the build-time gateway-
3002    /// artifact emission gate from the M3 declared-slot enumerator's
3003    /// kind-coherence gate, a two-consumer split far from the source
3004    /// `caixa.lisp` with no field naming the entry-drift root cause.
3005    /// Lifting the resolution rule to a typed method on the substrate
3006    /// primitive means every downstream consumer of the caixa's per-
3007    /// `Caixa` MESH-COMPOSITION external-gateway outer-composite
3008    /// surface reaches for exactly one typed dispatch — the resolver's
3009    /// accept-set migrates as a unit on any future axis addition.
3010    ///
3011    /// Fifth and final outer top-level [`Caixa`] `Option<&Composite>`-
3012    /// return composite-reference accessor — closes the outer-`Caixa`
3013    /// `Option<&Composite>` composite-reference sub-family opened by
3014    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) on the
3015    /// M2 Servico-runtime arm and extended onto the M3 mesh-slot arm
3016    /// by [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074),
3017    /// folds on the "one typed dispatch on the substrate primitive,
3018    /// thin projections at each consumer" discipline extended onto the
3019    /// third and final M3 mesh-slot axis. Peer of the closed inner
3020    /// mesh-slot outer-composite family the sibling
3021    /// [`crate::AplicacaoSpec::politicas`] (534dc21) /
3022    /// [`crate::AplicacaoSpec::placement`] (9abb8f0) /
3023    /// [`crate::AplicacaoSpec::entrada`] (d32111c) composite-reference
3024    /// accessor pins already close on the inner
3025    /// [`crate::AplicacaoSpec`] altitude — this lift closes the mirror
3026    /// sub-family on the outer top-level [`Caixa`] altitude, so both
3027    /// altitudes of the outer-composite reference-return discipline
3028    /// (per-`Caixa` outer-slot presence + per-`AplicacaoSpec` inner-
3029    /// slot presence) now carry the full five-arm accept-set behind a
3030    /// typed dispatch on the substrate primitive. Returns
3031    /// `Option<&Entrada>` (not the owning composite by copy or clone)
3032    /// because every downstream consumer of the entrada composite
3033    /// treats it as a read-only per-axis dispatch source — the
3034    /// reference-view is the narrowest borrow that supports every
3035    /// present + roadmapped consumer (per-axis accessor dispatch,
3036    /// serde composite-serialization on the programs.yaml overlay,
3037    /// presence-probe early return on the "author-omitted `:entrada`
3038    /// ⇒ cluster-internal Aplicacao" partition, `Aplicacao`-composition
3039    /// seed's forward arm) without cloning the composite through every
3040    /// consumer's fast path. The `Option` half of the return-type
3041    /// preserves the load-bearing "author-omitted `:entrada` ⇒
3042    /// cluster-internal Aplicacao" partition (not a default composite
3043    /// the downstream must reject on emptiness — a cluster-internal
3044    /// Aplicacao has no external gateway at all, not "a default gateway
3045    /// that emits nothing"); the accessor projects the raw
3046    /// `Option<Entrada>` slot's presence bit through the reference-
3047    /// return unchanged. Named `entrada()` to match the storage field's
3048    /// name verbatim and the tatara-lisp author-surface term
3049    /// (`:entrada`) the field's own docstring already carries.
3050    #[must_use]
3051    pub const fn entrada(&self) -> Option<&crate::aplicacao::Entrada> {
3052        self.entrada.as_ref()
3053    }
3054
3055    /// Substrate-canonical per-`Caixa` `:ci` slot accessor — returns the
3056    /// author-declared typed CI run (`canteiro_types::CiRun`) verbatim as
3057    /// an `Option<&CiRun>`, borrowed from the typed slot's own
3058    /// `Option<CiRun>` storage. `None` when the slot is absent (every
3059    /// non-`Acao` kind, and an `Acao` caixa that hasn't declared `:ci`
3060    /// yet — the latter is caught by [`crate::LayoutError::MissingCi`],
3061    /// not silently accepted).
3062    ///
3063    /// Named `ci()` to match the storage field's name and the
3064    /// tatara-lisp author surface (`:ci`); mirrors the sibling
3065    /// `Option<&Composite>` accessors on this same `Caixa` altitude
3066    /// ([`Self::limits`], [`Self::behavior`], [`Self::politicas`],
3067    /// [`Self::placement`], [`Self::entrada`]) — one typed dispatch on
3068    /// the substrate primitive rather than an open-coded `self.ci.as_ref()`
3069    /// at every consumer.
3070    #[must_use]
3071    pub const fn ci(&self) -> Option<&canteiro_types::CiRun> {
3072        self.ci.as_ref()
3073    }
3074
3075    /// Substrate-canonical per-`Caixa` `:estrategia` M2 supervisor-tree-
3076    /// slot flat-spread OTP-shaped sibling-restart-strategy discriminant
3077    /// accessor every consumer of the top-level manifest's per-Supervisor
3078    /// restart-strategy axis keys off — returns the author-declared
3079    /// `:estrategia` variant verbatim as an `Option<RestartStrategy>`,
3080    /// `Copy`-projected from the typed slot's own
3081    /// `Option<crate::supervisor::RestartStrategy>` storage. Optional
3082    /// (`:estrategia` is a flat-spread supervisor-only slot every
3083    /// non-`Supervisor`-kind `defcaixa` carries as `None` by
3084    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3085    /// still omit to defer to [`RestartStrategy::default`] —
3086    /// [`RestartStrategy::OneForOne`] — through the [`Self::supervisor_view`]
3087    /// `unwrap_or_default()` fold; a returned `None` degenerates to the
3088    /// [`SupervisorSpec::default`]-inherited strategy without any silent
3089    /// promotion to a fresh explicit variant at the accessor boundary).
3090    ///
3091    /// The `:estrategia` slot carries the M2 typed OTP-shaped sibling-
3092    /// restart-strategy discriminant every substrate-side per-Supervisor
3093    /// dispatch fans on (INSPIRATIONS §II.2 — OTP `supervisor:strategy`
3094    /// closed-set `one_for_one | one_for_all | rest_for_one |
3095    /// simple_one_for_one` algebra translated onto pleme-io's typed
3096    /// [`RestartStrategy`] enum; CAIXA-SDLC §II — the M2 supervisor-tree
3097    /// slot algebra the operator's hierarchical reconciliation scheduler
3098    /// fans on). The slot is *flat-spread* on the outer top-level `Caixa`
3099    /// (per the field-shape docstring at caixa-core/src/manifest.rs — "The
3100    /// supervisor slots are flat on Caixa (vs nested under a
3101    /// `SupervisorSpec` sub-form) to keep tatara-lisp authoring at one
3102    /// level of nesting"), so the accessor's altitude is the outer
3103    /// [`Caixa`] surface rather than the composed [`SupervisorSpec`]
3104    /// altitude the sibling [`crate::supervisor::SupervisorSpec::estrategia`]
3105    /// (eafb619) accessor keys off. The two typed axes — the outer
3106    /// author-surface `Option<RestartStrategy>` on the [`Caixa`] altitude
3107    /// (author-omitted arm carried as `None`) and the inner post-
3108    /// composition `RestartStrategy` on the [`SupervisorSpec`] altitude
3109    /// (`Option` collapsed through the [`Self::supervisor_view`]
3110    /// `unwrap_or_default()` fold) — now share one accessor discipline for
3111    /// the shared substrate concept "the author-declared OTP-shaped
3112    /// sibling-restart-strategy variant that partitions the downstream
3113    /// per-Supervisor renderer's per-arm fan-out"; the outer-altitude
3114    /// `None` arm is the pre-composition presence bit every declared-slot
3115    /// enumerator ([`Self::declared_supervisor_slots`]) reads, and the
3116    /// inner-altitude non-`Option` `RestartStrategy` is the post-
3117    /// composition partition-dispatch input every strategy-arm consumer
3118    /// ([`SupervisorSpec::validate`], the future wasm-operator's per-
3119    /// Supervisor sibling-restart branch, the future M4
3120    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
3121    /// webhook) fans on.
3122    ///
3123    /// Prior to this lift the `.estrategia` field was accessed inline at
3124    /// two production sites in `caixa-core/src/manifest.rs` — the
3125    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`
3126    /// presence-probe arm at `if self.estrategia.is_some()` (which drives
3127    /// the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3128    /// coherence gate's per-slot label push) and the [`Self::supervisor_view`]
3129    /// `SupervisorSpec` construction site at `estrategia:
3130    /// self.estrategia.unwrap_or_default()` (which composes the flat-
3131    /// spread outer author-surface `Option<RestartStrategy>` onto the
3132    /// inner post-composition [`SupervisorSpec`] `RestartStrategy` field
3133    /// the [`SupervisorSpec::estrategia`] accessor keys off) — two open-
3134    /// coded field-accesses that expressed no compile-time link back to
3135    /// the typed slot. A future extension of the outer `:estrategia` axis
3136    /// to a richer author surface (a per-cluster strategy override the
3137    /// operator pins through a future `:estrategia-overrides` overlay the
3138    /// MESH-COMPOSITION §III.2 supervision-canary roadmap acknowledges,
3139    /// a per-tenant strategy-alias table the M4 CR materializer resolves
3140    /// per-CR, a per-Supervisor dynamic strategy derivation the future
3141    /// adaptive-supervision engine computes from child-failure-history
3142    /// topology, a per-child-cohort strategy split the future
3143    /// `RestForCohort` extension the INSPIRATIONS.md §II.2 Erlang/OTP
3144    /// absorption roadmap acknowledges, a promotion of the plain
3145    /// `Option<RestartStrategy>` to a richer
3146    /// `AuthorDeclaredStrategy { declared, overlay }` newtype once the
3147    /// operator-resolved overlay lands) would have had to be threaded
3148    /// through both open-coded copies in lockstep or the enumerator's
3149    /// presence probe and the composition site's `unwrap_or_default()`
3150    /// fold would silently disagree on which strategy a given [`Caixa`]
3151    /// resolves to (an author's `:estrategia OneForAll` would satisfy
3152    /// the enumerator's presence probe while the composition site
3153    /// silently rendered a stale `OneForOne`, or vice versa). Lifting
3154    /// the resolution rule to a typed method on the substrate primitive
3155    /// means every downstream consumer of the caixa's per-`Caixa` outer-
3156    /// altitude sibling-restart-strategy surface reaches for exactly one
3157    /// typed dispatch — the resolver's accept-set migrates as a unit on
3158    /// any future axis addition.
3159    ///
3160    /// First outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3161    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3162    /// axes — opens the outer-`Caixa` `Option<Copy>` flat-spread
3163    /// projection pattern the sibling per-`Caixa` `:max-restarts`
3164    /// `Option<u32>` and (through the future duration-newtype landing)
3165    /// `:restart-window` `Option<Duration>` future outer-scalar lifts
3166    /// fold on. Peer of the inner-altitude [`crate::supervisor::SupervisorSpec::estrategia`]
3167    /// (eafb619) `Copy`-return sibling-restart-strategy scalar accessor on
3168    /// the post-composition [`SupervisorSpec`] altitude — same "one
3169    /// typed dispatch on the substrate primitive, thin projections at
3170    /// each consumer" discipline extended onto the pre-composition outer
3171    /// author-surface [`Caixa`] altitude for the same OTP-shaped
3172    /// sibling-restart-strategy axis. Peer of the closed outer-`Caixa`
3173    /// `Option<&Composite>` composite-reference family the sibling
3174    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3175    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3176    /// [`Self::entrada`] (e4128e4) accessor pins already carry on the
3177    /// outer `Option<&Composite>` altitude — extends the outer-`Caixa`
3178    /// typed-slot accessor discipline onto the flat-spread M2 supervisor-
3179    /// tree `Option<Copy>`-discriminant sub-family the sibling M3
3180    /// [`crate::aplicacao::Placement::estrategia`] (921fe1b)
3181    /// `PlacementStrategy` `Copy`-composite-enum scalar accessor already
3182    /// pins on the inner-altitude per-`:placement` composite. Named
3183    /// `estrategia()` to match the storage field's name and the
3184    /// per-[`SupervisorSpec`] peer [`crate::supervisor::SupervisorSpec::estrategia`]
3185    /// / per-[`crate::aplicacao::Placement`] peer
3186    /// [`crate::aplicacao::Placement::estrategia`] method-name discipline
3187    /// verbatim; the accessor's identity name maps onto the canonical
3188    /// OTP-shape supervision vocabulary the [`RestartStrategy`] enum's
3189    /// docstring already carries.
3190    #[must_use]
3191    pub const fn estrategia(&self) -> Option<crate::supervisor::RestartStrategy> {
3192        self.estrategia
3193    }
3194
3195    /// Substrate-canonical per-`Caixa` `:max-restarts` M2 supervisor-tree-
3196    /// slot flat-spread OTP-`MaxIntensity`-shaped restart-budget-count
3197    /// scalar accessor every consumer of the top-level manifest's per-
3198    /// Supervisor `:max-restarts` restart-budget-count axis keys off —
3199    /// returns the author-declared `:max-restarts` typed `Option<u32>`
3200    /// verbatim, `Copy`-projected from the typed slot's own `Option<u32>`
3201    /// storage (`u32` is `Copy`, so `Option<u32>` is `Copy` and the
3202    /// accessor returns by value; no borrow of `&self` past the call).
3203    /// Optional (`:max-restarts` is a flat-spread supervisor-only slot
3204    /// every non-`Supervisor`-kind `defcaixa` carries as `None` by
3205    /// `#[serde(default)]`, and every `Supervisor`-kind `defcaixa` may
3206    /// still omit to defer to the [`Self::supervisor_view`]
3207    /// `unwrap_or(5)` fold's OTP-canonical `{intensity, 5, 60}` default).
3208    ///
3209    /// The `:max-restarts` slot carries the M2 typed Erlang/OTP-shaped
3210    /// `MaxIntensity` restart-budget count that pairs with the sibling
3211    /// `:restart-window` `Period` to form the `MaxIntensity / Period`
3212    /// restart-intensity ratio the supervisor trips its own escalation on
3213    /// (INSPIRATIONS §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}`
3214    /// worker-supervisor default; RUNTIME-PATTERNS §II.2; CAIXA-SDLC §II
3215    /// — the M2 supervisor-tree slot algebra the operator's hierarchical
3216    /// reconciliation scheduler fans on). The slot is *flat-spread* on
3217    /// the outer top-level `Caixa` (per the field-shape docstring at
3218    /// caixa-core/src/manifest.rs — "The supervisor slots are flat on
3219    /// Caixa (vs nested under a `SupervisorSpec` sub-form)"), so the
3220    /// accessor's altitude is the outer [`Caixa`] surface rather than the
3221    /// composed [`SupervisorSpec`] altitude the sibling
3222    /// [`crate::supervisor::SupervisorSpec::max_restarts`] accessor keys
3223    /// off. The two typed axes — the outer author-surface `Option<u32>`
3224    /// on the [`Caixa`] altitude (author-omitted arm carried as `None`)
3225    /// and the inner post-composition `u32` on the [`SupervisorSpec`]
3226    /// altitude (`Option` collapsed through the [`Self::supervisor_view`]
3227    /// `unwrap_or(5)` fold) — now share one accessor discipline for the
3228    /// shared substrate concept "the author-declared OTP-shaped
3229    /// restart-budget count every downstream per-Supervisor consumer's
3230    /// restart-intensity budget-vs-count comparator fans on".
3231    ///
3232    /// Prior to this lift the `.max_restarts` field was accessed inline
3233    /// at two production sites in `caixa-core/src/manifest.rs` — the
3234    /// [`Self::declared_supervisor_slots`] `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`
3235    /// presence-probe arm at `if self.max_restarts.is_some()` (which
3236    /// drives the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3237    /// kind-coherence gate's per-slot label push) and the
3238    /// [`Self::supervisor_view`] `SupervisorSpec` construction site at
3239    /// `max_restarts: self.max_restarts.unwrap_or(5)` (which composes the
3240    /// flat-spread outer author-surface `Option<u32>` onto the inner
3241    /// post-composition [`SupervisorSpec`] `u32` field the
3242    /// [`SupervisorSpec::max_restarts`] accessor keys off) — two open-
3243    /// coded field-accesses that expressed no compile-time link back to
3244    /// the typed slot. A future extension of the outer `:max-restarts`
3245    /// axis to a richer author surface (a per-cluster restart-budget
3246    /// override the operator pins through a future `:max-restarts-overrides`
3247    /// overlay the MESH-COMPOSITION §III.2 supervision-canary roadmap
3248    /// acknowledges, a per-tenant restart-budget-alias table the M4 CR
3249    /// materializer resolves per-CR, a per-Supervisor dynamic restart-
3250    /// budget derivation the future adaptive-supervision engine computes
3251    /// from child-failure-history topology, a promotion of the plain
3252    /// `Option<u32>` count to a richer `{MaxR, MaxT}` per-child-cohort
3253    /// restart-budget-partition once the INSPIRATIONS §II.2 Erlang/OTP
3254    /// per-child-cohort roadmap lands) would have had to be threaded
3255    /// through both open-coded copies in lockstep or the enumerator's
3256    /// presence probe and the composition site's `unwrap_or(5)` fold
3257    /// would silently disagree on which restart-budget a given [`Caixa`]
3258    /// resolves to (an author's `:max-restarts 10` would satisfy the
3259    /// enumerator's presence probe while the composition site silently
3260    /// composed the OTP-canonical `5`, or vice versa). Lifting the
3261    /// resolution rule to a typed method on the substrate primitive means
3262    /// every downstream consumer of the caixa's per-`Caixa` outer-altitude
3263    /// restart-budget-count surface reaches for exactly one typed dispatch
3264    /// — the resolver's accept-set migrates as a unit on any future axis
3265    /// addition.
3266    ///
3267    /// Second outer top-level [`Caixa`] `Option<Copy>`-return supervisor-
3268    /// tree-slot flat-spread accessor for M2 supervisor-slot Copy-carry
3269    /// axes — folds on the outer-`Caixa` `Option<Copy>` flat-spread
3270    /// projection pattern the sibling per-`Caixa`
3271    /// [`Self::estrategia`] (ed04d3c) accessor opened, extends the
3272    /// sub-family onto the sibling `Option<u32>` restart-budget-count arm.
3273    /// Peer of the inner-altitude
3274    /// [`crate::supervisor::SupervisorSpec::max_restarts`] `u32` accessor
3275    /// on the post-composition [`SupervisorSpec`] altitude — same "one
3276    /// typed dispatch on the substrate primitive, thin projections at
3277    /// each consumer" discipline extended onto the pre-composition outer
3278    /// author-surface [`Caixa`] altitude for the same OTP-`MaxIntensity`-
3279    /// shaped restart-budget-count axis. Named `max_restarts()` to match
3280    /// the storage field's name and the per-[`SupervisorSpec`] peer
3281    /// [`crate::supervisor::SupervisorSpec::max_restarts`] method-name
3282    /// discipline verbatim; the accessor's identity maps onto the
3283    /// canonical OTP-shape supervision vocabulary the `:max-restarts`
3284    /// field's docstring already carries.
3285    #[must_use]
3286    pub const fn max_restarts(&self) -> Option<u32> {
3287        self.max_restarts
3288    }
3289
3290    /// Substrate-canonical per-`Caixa` `:restart-window` M2 supervisor-
3291    /// tree-slot flat-spread OTP-`Period`-shaped restart-intensity-
3292    /// denominator raw-duration-string scalar accessor every consumer of
3293    /// the top-level manifest's per-Supervisor `:restart-window` sliding-
3294    /// window axis keys off — returns the author-declared `:restart-window`
3295    /// typed `Option<String>` verbatim as an `Option<&str>`, borrowed
3296    /// from the typed slot's own `Option<String>` storage. `None` when
3297    /// the slot is absent (the canonical "never reset — every restart
3298    /// across the supervisor's lifetime counts against the sibling
3299    /// `:max-restarts` budget" sentinel every non-`Supervisor`-kind
3300    /// `defcaixa` carries by `#[serde(default)]` and every
3301    /// `Supervisor`-kind `defcaixa` may still omit to defer to the
3302    /// [`Self::supervisor_view`] `restart_window: None` composition
3303    /// through the [`crate::supervisor::duration_codec::parse`] soft-
3304    /// swallow `.and_then(|s| … .ok())` fold).
3305    ///
3306    /// The `:restart-window` slot carries the raw M2 typed Erlang/OTP-
3307    /// shaped `Period` sliding-observation-interval duration string that
3308    /// pairs with the sibling `:max-restarts` `MaxIntensity` restart-
3309    /// budget count to form the `MaxIntensity / Period` restart-intensity
3310    /// ratio the supervisor trips its own escalation on (INSPIRATIONS
3311    /// §II.2 — Erlang/OTP `supervisor` `{intensity, 5, 60}` worker-
3312    /// supervisor default; RUNTIME-PATTERNS §II.2). The outer-`Caixa`
3313    /// slot stores the raw duration string (`"60s"`, `"5m"`, `"500ms"`)
3314    /// authored under `:restart-window` — the typed [`SupervisorSpec`]
3315    /// holds an `Option<Duration>` routed through the shared
3316    /// [`crate::supervisor::duration_codec`] via `with = "duration_codec"`
3317    /// — so the outer altitude's accessor returns `Option<&str>` (raw
3318    /// authoring surface) while the inner altitude's
3319    /// [`crate::supervisor::SupervisorSpec::restart_window`] returns
3320    /// `Option<Duration>` (parsed typed surface). The parse-refusal arm
3321    /// is closed by the sibling [`Self::validate_restart_window`] gate
3322    /// that surfaces [`ManifestError::RestartWindowMalformed`] naming
3323    /// the offending value; the view-construction path
3324    /// [`Self::supervisor_view`] soft-swallows the same parse error to
3325    /// `None` to keep the view best-effort.
3326    ///
3327    /// Prior to this lift the `.restart_window` field was accessed inline
3328    /// at three production sites in `caixa-core/src/manifest.rs` — the
3329    /// [`Self::declared_supervisor_slots`]
3330    /// `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` presence-probe arm at
3331    /// `if self.restart_window.is_some()` (which drives the
3332    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
3333    /// coherence gate's per-slot label push), the
3334    /// [`Self::validate_restart_window`] `let Some(s) =
3335    /// self.restart_window.as_deref()` empty-and-shape gate binding
3336    /// (which folds the raw string through the shared
3337    /// [`crate::supervisor::duration_codec::parse`] to surface
3338    /// [`ManifestError::RestartWindowMalformed`] naming the offending
3339    /// value), and the [`Self::supervisor_view`] `self.restart_window
3340    /// .as_deref().and_then(…)` view-construction fold (which composes
3341    /// the flat-spread outer author-surface `Option<String>` onto the
3342    /// inner post-composition [`SupervisorSpec`] `Option<Duration>`
3343    /// field the [`SupervisorSpec::restart_window`] accessor keys off) —
3344    /// three open-coded field-accesses that expressed no compile-time
3345    /// link back to the typed slot. A future extension of the outer
3346    /// `:restart-window` axis to a richer author surface (a per-cluster
3347    /// window override, a per-tenant window-alias table, a per-Supervisor
3348    /// dynamic window derivation the future adaptive-supervision engine
3349    /// computes from child-failure-history topology, a promotion of the
3350    /// plain `Option<String>` raw duration to a typed `Option<Duration>`
3351    /// once the future author-surface parser lands at the [`Caixa`]
3352    /// altitude and the raw-string form is retired) would have had to be
3353    /// threaded through every open-coded copy in lockstep or the three
3354    /// consumers would silently disagree on which raw string a given
3355    /// [`Caixa`] resolves to. Lifting the resolution rule to a typed
3356    /// method on the substrate primitive means every downstream consumer
3357    /// of the caixa's per-`Caixa` outer-altitude restart-window raw-
3358    /// string surface reaches for exactly one typed dispatch — the
3359    /// resolver's accept-set migrates as a unit on any future axis
3360    /// addition.
3361    ///
3362    /// Third outer top-level [`Caixa`] supervisor-tree-slot flat-spread
3363    /// accessor — folds on the outer-`Caixa` M2 supervisor-tree flat-
3364    /// spread projection pattern the sibling per-`Caixa`
3365    /// [`Self::estrategia`] (ed04d3c) `Option<Copy>` and
3366    /// [`Self::max_restarts`] `Option<Copy>` accessors opened, extends
3367    /// the sub-family onto the sibling `Option<&str>` raw-duration-
3368    /// string arm (the outer altitude's raw-string form; the inner
3369    /// altitude's parsed [`Duration`] form is the peer
3370    /// [`crate::supervisor::SupervisorSpec::restart_window`] accessor).
3371    /// Peer of the sibling per-`Caixa` `Option<&str>`-return scalar
3372    /// accessors ([`Self::licenca`] / [`Self::repositorio`] /
3373    /// [`Self::descricao`] / [`Self::edicao`]) on the universal-axis
3374    /// outer scalar-projection family the outer-`Caixa` `Option<&str>`
3375    /// sub-family already carries — same "one typed dispatch on the
3376    /// substrate primitive, thin projections at each consumer"
3377    /// discipline extended onto the M2 supervisor-tree flat-spread
3378    /// `Option<&str>` raw-duration-string arm. Named `restart_window()`
3379    /// to match the storage field's name and the per-[`SupervisorSpec`]
3380    /// peer [`crate::supervisor::SupervisorSpec::restart_window`]
3381    /// method-name discipline verbatim; the accessor's identity maps
3382    /// onto the canonical OTP-shape supervision vocabulary the
3383    /// `:restart-window` field's docstring already carries.
3384    #[must_use]
3385    pub const fn restart_window(&self) -> Option<&str> {
3386        match &self.restart_window {
3387            Some(s) => Some(s.as_str()),
3388            None => None,
3389        }
3390    }
3391
3392    /// Substrate-canonical per-`Caixa` `:upgrade-from` M2 typed-slot
3393    /// outer-composite OTP-appup-shaped per-prior-version migration-
3394    /// entry-list slice accessor every consumer of the top-level
3395    /// manifest's per-Servico hot-upgrade-block `&[UpgradeFromEntry]`
3396    /// slice-view keys off — returns the author-declared `:upgrade-from`
3397    /// typed `Vec<UpgradeFromEntry>` verbatim as a
3398    /// `&[UpgradeFromEntry]` slice-view over the same backing buffer
3399    /// the raw `self.upgrade_from.as_slice()` field access borrows
3400    /// from. Empty-slice-carrying (the "no hot-upgrade path declared"
3401    /// arm every `defcaixa` without an `:upgrade-from` block carries;
3402    /// the [`Self::from_lisp`] derive folds an omitted `:upgrade-from`
3403    /// through `#[serde(default)]` to `Vec::new()`, so a `Caixa` past
3404    /// parse definitionally carries a `Vec<UpgradeFromEntry>` slot —
3405    /// possibly empty — and the returned `&[UpgradeFromEntry]`
3406    /// degenerates to an empty slice on that arm without any silent
3407    /// `None` collapse).
3408    ///
3409    /// The outer `:upgrade-from` slot carries the M2 typed OTP-appup
3410    /// migration block — the load-bearing container of every per-
3411    /// prior-`:versao` migration-instruction list the wasm-operator
3412    /// dispatches on at hot-upgrade time (INSPIRATIONS §II.4 — OTP
3413    /// `.appup` per-prior-version `LoadModule | StateChange |
3414    /// SoftPurge | Purge | Restart` instruction algebra translated
3415    /// onto pleme-io's typed `:upgrade-from :from` + `:instructions`
3416    /// entry list; CAIXA-SDLC §II — the typed-M2 slot algebra the
3417    /// operator's hot-upgrade dispatch fans on). Every per-entry axis
3418    /// threads through a lifted per-entry accessor on the
3419    /// [`UpgradeFromEntry`] type: the
3420    /// [`UpgradeFromEntry::prior_versao`] SemVer-shaped previous-
3421    /// version scalar accessor and the
3422    /// [`UpgradeFromEntry::instructions`] `&[UpgradeInstruction]`-
3423    /// return per-entry instruction-list accessor (0137e5a). Every
3424    /// downstream consumer of the hot-upgrade path first passes
3425    /// through this outer accessor onto the slice and then dispatches
3426    /// per-entry through the inner accessors — the two-level dispatch
3427    /// means every per-`:upgrade-from` reader now routes through a
3428    /// typed dispatch on the substrate primitive at both altitudes.
3429    ///
3430    /// Prior to this lift the `.upgrade_from` `Vec<UpgradeFromEntry>`
3431    /// slot was accessed inline at production sites across three
3432    /// files — the [`Self::declared_servico_slots`] M2 declared-slot
3433    /// enumerator's `self.upgrade_from.is_empty()` presence probe
3434    /// (caixa-core/src/manifest.rs, which drives the
3435    /// `M2_AUTHOR_KEY_UPGRADE_FROM` kebab-case author-label push every
3436    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
3437    /// gate reads), the [`crate::StandardLayout::verify`] per-
3438    /// `:upgrade-from` three-stage validation pass (caixa-core/src/
3439    /// layout.rs, which fans onto the
3440    /// [`crate::upgrade::validate_upgrade_from`] per-entry shape +
3441    /// cross-entry duplicate gate, the
3442    /// [`crate::upgrade::validate_upgrade_from_against_versao`]
3443    /// SemVer-precedence cross-slot gate, the
3444    /// [`crate::upgrade::validate_upgrade_from_against_behavior`]
3445    /// `:state-change` ↔ `:on-state-change` cross-slot composition
3446    /// gate, and the per-instruction script-path existence-probe walk
3447    /// that reads each entry's [`UpgradeFromEntry::instructions`] to
3448    /// resolve every declared migration script against the layout
3449    /// root), and the [`crate::render::servico_m2_overlay`] per-
3450    /// Servico M2 overlay emitter's `!caixa.upgrade_from.is_empty()`
3451    /// presence gate + `serde_yaml::to_value(&caixa.upgrade_from)`
3452    /// projection (caixa-core/src/render.rs, which drives the
3453    /// `M2_KEY_UPGRADE_FROM`-keyed `serde_yaml` projection every
3454    /// `caixa-helm` / `caixa-flux` Servico values-block emitter fans
3455    /// on and lands as the ComputeUnit CR's `spec.upgradeFrom` field).
3456    /// A future extension of the outer `:upgrade-from` axis (a per-
3457    /// cluster `:upgrade-overrides` overlay the wasm-engine operator
3458    /// resolves at admission time so a cluster-specific migration
3459    /// policy can tighten a caixa-declared step without re-authoring
3460    /// the `caixa.lisp`, promotion of the plain
3461    /// `Vec<UpgradeFromEntry>` to a richer `{static, dynamic}`
3462    /// partition once runtime-resolved hot-upgrade instructions land,
3463    /// per-entry priority annotation once multi-strategy fan-out
3464    /// lands) would have had to be threaded through all six open-
3465    /// coded copies in lockstep or one consumer would silently
3466    /// disagree with the peers on which upgrade slice a given Caixa
3467    /// resolves to — a six-consumer split at the enumerator, the
3468    /// three-stage validate pass, the script-path probe walk, and the
3469    /// M2 overlay emitter, far from the source `caixa.lisp` with no
3470    /// field naming the upgrade-drift root cause. Lifting the
3471    /// resolution rule to a typed method on the substrate primitive
3472    /// means every downstream consumer of the caixa's per-`Caixa`
3473    /// OTP-appup outer-slice surface reaches for exactly one typed
3474    /// dispatch — the resolver's accept-set migrates as a unit on any
3475    /// future axis addition.
3476    ///
3477    /// First outer top-level [`Caixa`] `&[Composite]`-return slice
3478    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the
3479    /// outer-`Caixa` `&[Composite]` composite-slice projection
3480    /// pattern the sibling `:children`
3481    /// [`crate::supervisor::ChildSpec`] / `:membros`
3482    /// [`crate::aplicacao::Membro`] / `:contratos`
3483    /// [`crate::aplicacao::WitContract`] future outer-composite-slice
3484    /// lifts fold on. Peer of the closed outer-`Caixa` scalar
3485    /// `Option<&Composite>` composite-reference family the sibling
3486    /// [`Self::limits`] (b2bd9d7) / [`Self::behavior`] (35d8b52) /
3487    /// [`Self::politicas`] (5d23d29) / [`Self::placement`] (4fb8074) /
3488    /// [`Self::entrada`] (e4128e4) accessors closed on the outer
3489    /// `Option<&Composite>` altitude, extended here to the outer-
3490    /// `Caixa` `&[Composite]` vec-carry altitude. Peer at the inner
3491    /// altitude of [`crate::upgrade::UpgradeFromEntry::instructions`]
3492    /// (0137e5a) — same "one typed dispatch on the substrate
3493    /// primitive, thin projections at each consumer" discipline
3494    /// folded onto the outer top-level [`Caixa`] altitude, opening the
3495    /// M2 vec-carry slot family's outer-composite-slice axis. Sibling
3496    /// in shape to the peer outer-`Caixa` `&[Dep]`-return
3497    /// [`Self::deps`] (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and
3498    /// `&[String]`-return [`Self::autores`] (b5d813f) /
3499    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`]
3500    /// (8a36c23) / [`Self::exe`] (65d9527) / [`Self::servicos`]
3501    /// (611f78b) slice-accessors on the sibling outer-`Caixa` scalar-
3502    /// element vec-carry axes — folds the "outer [`Caixa`] `&[T]`
3503    /// slice" projection pattern onto the sibling M2 typed-composite-
3504    /// element axis (`UpgradeFromEntry` composite, matching the
3505    /// per-inner [`UpgradeFromEntry::instructions`] element type at a
3506    /// different altitude).
3507    ///
3508    /// Returns `&[UpgradeFromEntry]` (not `&Vec<UpgradeFromEntry>`)
3509    /// because every downstream consumer of the hot-upgrade list
3510    /// treats it as a read-only sequence — the slice-view is the
3511    /// narrowest borrow that supports every present + roadmapped
3512    /// consumer (`.iter()`, `.len()`, `.is_empty()`, `serde` slice-
3513    /// serialization through
3514    /// `serde_yaml::to_value(&[UpgradeFromEntry])`) without leaking
3515    /// the backing `Vec`'s grow/push/reserve surface no consumer of
3516    /// the typed view reaches for (the storage-side `Vec` remains
3517    /// reachable through the `pub upgrade_from` field for the
3518    /// mutation-carrying serde round-trip and per-test fixture-
3519    /// mutation paths). Named `upgrade_from()` to match the storage
3520    /// field's `snake_case` name; the kebab-case author-surface tag
3521    /// `:upgrade-from` is the same axis after tatara-lisp's
3522    /// kebab↔snake fold and the accessor's identity maps onto the
3523    /// canonical CAIXA-SDLC §II vocabulary the slot's docstring
3524    /// already carries.
3525    #[must_use]
3526    pub const fn upgrade_from(&self) -> &[UpgradeFromEntry] {
3527        self.upgrade_from.as_slice()
3528    }
3529
3530    /// Substrate-canonical per-`Caixa` `:children` M2 supervisor-tree-
3531    /// slot outer-composite OTP-shaped per-supervisor static-child-list
3532    /// slice accessor every consumer of the top-level manifest's per-
3533    /// Supervisor `&[ChildSpec]` slice-view keys off — returns the
3534    /// author-declared `:children` typed `Vec<crate::supervisor::ChildSpec>`
3535    /// verbatim as a `&[crate::supervisor::ChildSpec]` slice-view over
3536    /// the same backing buffer the raw `self.children.as_slice()` field
3537    /// access borrows from. Empty-slice-carrying (the "no static children
3538    /// declared" arm every non-`Supervisor`-kind `defcaixa` carries by
3539    /// #[serde(default)] and every `SimpleOneForOne` supervisor carries
3540    /// by [`crate::supervisor::SupervisorError::SimpleOneForOneWithStaticChildren`]
3541    /// gate; the returned `&[ChildSpec]` degenerates to an empty slice
3542    /// on those arms without any silent `None` collapse).
3543    ///
3544    /// The outer `:children` slot carries the M2 typed OTP-supervisor
3545    /// static-child list — the load-bearing container of every per-
3546    /// child `{caixa, versao, restart}` triple the wasm-operator's
3547    /// hierarchical reconciler dispatches on at supervisor-tree
3548    /// materialization time (INSPIRATIONS §II.2 — OTP `supervisor:init/1`
3549    /// static-child list translated onto pleme-io's typed
3550    /// [`crate::supervisor::ChildSpec`] entry list; CAIXA-SDLC §II —
3551    /// the typed-M2 slot algebra the operator's per-supervisor fan-out
3552    /// dispatch fans on). Every per-child axis threads through a lifted
3553    /// per-entry accessor on the [`crate::supervisor::ChildSpec`] type:
3554    /// the [`crate::supervisor::ChildSpec::nome`] DNS-1123-label
3555    /// child-caixa-identity scalar accessor, the peer versao SemVer-2
3556    /// version-requirement scalar accessor, and the
3557    /// [`crate::supervisor::ChildSpec::restart`] `Copy`-composite-enum
3558    /// per-child post-exit restart-decision-policy discriminant
3559    /// accessor (dfb4a81). Every downstream consumer of the supervisor-
3560    /// tree path first passes through this outer accessor onto the
3561    /// slice and then dispatches per-child through the inner accessors
3562    /// — the two-level dispatch means every per-`:children` reader now
3563    /// routes through a typed dispatch on the substrate primitive at
3564    /// both altitudes.
3565    ///
3566    /// Prior to this lift the `.children` `Vec<ChildSpec>` slot was
3567    /// accessed inline at three production sites across two files —
3568    /// the [`Self::declared_supervisor_slots`] supervisor-tree
3569    /// declared-slot enumerator's `!self.children.is_empty()` presence
3570    /// probe (caixa-core/src/manifest.rs, which drives the
3571    /// `SUPERVISOR_AUTHOR_KEY_CHILDREN` kebab-case author-label push
3572    /// every [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
3573    /// kind-coherence gate reads), the [`Self::supervisor_view`]
3574    /// per-supervisor typed-view composer's `self.children.clone()`
3575    /// per-child fold-in path (caixa-core/src/manifest.rs, which
3576    /// materializes the typed [`crate::supervisor::SupervisorSpec`]
3577    /// view every [`crate::StandardLayout::verify`] Supervisor-arm gate
3578    /// dispatches on), and the [`crate::StandardLayout::verify`] per-
3579    /// `:children :caixa` self-parent refusal probe's
3580    /// `&caixa.children`-borrowed
3581    /// [`crate::supervisor::validate_no_self_supervision`] input
3582    /// (caixa-core/src/layout.rs, which pins the "no child names the
3583    /// supervisor's own `:nome`" cross-slot coherence gate). A future
3584    /// extension of the outer `:children` axis (a per-cluster
3585    /// `:children-overrides` overlay the wasm-engine operator resolves
3586    /// at admission time so a cluster-specific child-set can tighten
3587    /// a caixa-declared list without re-authoring the `caixa.lisp`,
3588    /// promotion of the plain `Vec<ChildSpec>` to a richer
3589    /// `{static, dynamic}` partition once Erlang/OTP's
3590    /// `simple_one_for_one`-shaped dynamic-child slot lands as a typed
3591    /// axis, per-child priority annotation once multi-strategy fan-out
3592    /// lands) would have had to be threaded through all three open-
3593    /// coded copies in lockstep or one consumer would silently
3594    /// disagree with the peers on which child slice a given Caixa
3595    /// resolves to — the enumerator's presence probe reading the raw
3596    /// slot while the peer view-composer's fold-in path read an
3597    /// operator-resolved slot would silently split the paired
3598    /// declared-slot enumerator and typed-view composition, and the
3599    /// [`crate::supervisor::validate_no_self_supervision`] self-parent
3600    /// refusal probe reading a third borrow would silently drift the
3601    /// cross-slot coherence gate's traversal input from the two peers,
3602    /// a three-consumer split at the enumerator, the view composer,
3603    /// and the self-parent gate far from the source `caixa.lisp` with
3604    /// no field naming the child-set-drift root cause. Lifting the
3605    /// resolution rule to a typed method on the substrate primitive
3606    /// means every downstream consumer of the caixa's per-`Caixa`
3607    /// OTP-supervisor outer-slice surface reaches for exactly one
3608    /// typed dispatch — the resolver's accept-set migrates as a unit
3609    /// on any future axis addition.
3610    ///
3611    /// Second outer top-level [`Caixa`] `&[Composite]`-return slice
3612    /// accessor for M2 / M3 typed-slot vec-carry axes — folds on the
3613    /// outer-`Caixa` `&[Composite]` composite-slice sub-family the
3614    /// sibling [`Self::upgrade_from`] (2a1f907) accessor opened, peer
3615    /// at the outer altitude of the closed inner-`SupervisorSpec`
3616    /// [`crate::SupervisorSpec::children`] (bc92bce) accessor on the
3617    /// same OTP-supervisor static-child-list axis — same "byte-equal,
3618    /// borrow-shared" outer-accessor discipline extended onto the
3619    /// second outer-`Caixa` `&[Composite]` vec-carry axis. Sibling in
3620    /// shape to the peer outer-`Caixa` `&[Dep]`-return [`Self::deps`]
3621    /// (ad34b4e) / [`Self::deps_dev`] (f7fd81e) and `&[String]`-return
3622    /// [`Self::autores`] (b5d813f) / [`Self::etiquetas`] (78c7d3c) /
3623    /// [`Self::bibliotecas`] (8a36c23) / [`Self::exe`] (65d9527) /
3624    /// [`Self::servicos`] (611f78b) slice-accessors on the sibling
3625    /// outer-`Caixa` scalar-element vec-carry axes — folds the "outer
3626    /// [`Caixa`] `&[T]` slice" projection pattern onto the sibling
3627    /// M2 typed-composite-element axis
3628    /// ([`crate::supervisor::ChildSpec`] composite, matching the
3629    /// per-inner [`crate::SupervisorSpec::children`] element type at a
3630    /// different altitude).
3631    ///
3632    /// Returns `&[crate::supervisor::ChildSpec]` (not
3633    /// `&Vec<ChildSpec>`) because every downstream consumer of the
3634    /// child list treats it as a read-only sequence — the slice-view
3635    /// is the narrowest borrow that supports every present +
3636    /// roadmapped consumer (`.iter()`, `.len()`, `.is_empty()`, the
3637    /// [`crate::supervisor::validate_no_self_supervision`] `&[ChildSpec]`
3638    /// input, `serde` slice-serialization) without leaking the backing
3639    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3640    /// reaches for (the storage-side `Vec` remains reachable through
3641    /// the `pub children` field for the mutation-carrying serde round-
3642    /// trip and per-test fixture-mutation paths, including the
3643    /// [`Self::supervisor_view`] fold-in path that clones the slot
3644    /// into the typed view). Named `children()` to match the storage
3645    /// field's name verbatim and the tatara-lisp author-surface term
3646    /// (`:children`) the field's own docstring already carries; the
3647    /// accessor's identity maps onto the canonical OTP supervision
3648    /// vocabulary the [`Caixa::children`] field's docstring already
3649    /// reaches for ("Static children of a supervisor").
3650    #[must_use]
3651    pub const fn children(&self) -> &[crate::supervisor::ChildSpec] {
3652        self.children.as_slice()
3653    }
3654
3655    /// Substrate-canonical per-`Caixa` `:membros` M3 mesh-slot outer-
3656    /// composite MESH-COMPOSITION-shaped per-Aplicacao member-list slice
3657    /// accessor every consumer of the top-level manifest's per-Aplicacao
3658    /// `&[crate::aplicacao::Membro]` slice-view keys off — returns the
3659    /// author-declared `:membros` typed `Vec<crate::aplicacao::Membro>`
3660    /// verbatim as a `&[crate::aplicacao::Membro]` slice-view over the
3661    /// same backing buffer the raw `self.membros.as_slice()` field access
3662    /// borrows from. Empty-slice-carrying (the "no members declared" arm
3663    /// every non-`Aplicacao`-kind `defcaixa` carries by `#[serde(default)]`
3664    /// and every partially-authored Aplicacao carries before the
3665    /// [`crate::AplicacaoError::MembrosEmpty`] gate fires; the returned
3666    /// `&[Membro]` degenerates to an empty slice on those arms without any
3667    /// silent `None` collapse).
3668    ///
3669    /// The outer `:membros` slot carries the M3 typed MESH-COMPOSITION
3670    /// per-Aplicacao member list — the load-bearing container of every
3671    /// per-member `{caixa, versao}` pair the caixa-mesh renderer's
3672    /// per-Aplicacao program-emission dispatch fans on at mesh-artifact
3673    /// materialization time (MESH-COMPOSITION §III.1 — the typed graph's
3674    /// vertex set the `:contratos` `:de`/`:para` edges resolve against and
3675    /// the `:entrada :para` external-gateway destination validates
3676    /// against; CAIXA-SDLC §II — the typed-M3 slot algebra the operator's
3677    /// per-Aplicacao fan-out dispatch fans on). Every per-member axis
3678    /// threads through a lifted per-entry accessor on the
3679    /// [`crate::aplicacao::Membro`] type: the
3680    /// [`crate::aplicacao::Membro::nome`] DNS-1123-label member-caixa-
3681    /// identity scalar accessor (4a32abf) and the peer
3682    /// [`crate::aplicacao::Membro::versao_requirement`] SemVer-2
3683    /// version-requirement scalar accessor (a40b0e3). Every downstream
3684    /// consumer of the mesh-graph path first passes through this outer
3685    /// accessor onto the slice and then dispatches per-member through
3686    /// the inner accessors — the two-level dispatch means every per-
3687    /// `:membros` reader now routes through a typed dispatch on the
3688    /// substrate primitive at both altitudes.
3689    ///
3690    /// Prior to this lift the `.membros` `Vec<Membro>` slot was accessed
3691    /// inline at three production sites across two files — the
3692    /// [`Self::declared_mesh_slots`] mesh-slot declared-slot
3693    /// enumerator's `!self.membros.is_empty()` presence probe
3694    /// (caixa-core/src/manifest.rs, which drives the
3695    /// `M3_AUTHOR_KEY_MEMBROS` kebab-case author-label push every
3696    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3697    /// gate reads), the [`Self::aplicacao_view`] per-Aplicacao typed-view
3698    /// composer's `self.membros.clone()` per-member fold-in path
3699    /// (caixa-core/src/manifest.rs, which materializes the typed
3700    /// [`crate::aplicacao::AplicacaoSpec`] view every
3701    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate dispatches
3702    /// on), and the [`crate::StandardLayout::verify`] per-`:membros
3703    /// :caixa` self-membership refusal probe's `&caixa.membros`-borrowed
3704    /// [`crate::aplicacao::validate_no_self_membership`] input
3705    /// (caixa-core/src/layout.rs, which pins the "no member names the
3706    /// Aplicacao's own `:nome`" cross-slot coherence gate). A future
3707    /// extension of the outer `:membros` axis (a per-cluster
3708    /// `:membros-overrides` overlay the wasm-engine operator resolves at
3709    /// admission time so a cluster-specific member-set can tighten a
3710    /// caixa-declared list without re-authoring the `caixa.lisp`,
3711    /// promotion of the plain `Vec<Membro>` to a richer
3712    /// `{static, dynamic}` partition once runtime-resolved Aplicacao
3713    /// members land as a typed axis, per-member priority annotation once
3714    /// multi-strategy fan-out lands) would have had to be threaded
3715    /// through all three open-coded copies in lockstep or one consumer
3716    /// would silently disagree with the peers on which member slice a
3717    /// given Caixa resolves to — the enumerator's presence probe reading
3718    /// the raw slot while the peer view-composer's fold-in path read an
3719    /// operator-resolved slot would silently split the paired
3720    /// declared-slot enumerator and typed-view composition, and the
3721    /// [`crate::aplicacao::validate_no_self_membership`] self-membership
3722    /// refusal probe reading a third borrow would silently drift the
3723    /// cross-slot coherence gate's traversal input from the two peers, a
3724    /// three-consumer split at the enumerator, the view composer, and
3725    /// the self-membership gate far from the source `caixa.lisp` with no
3726    /// field naming the member-set-drift root cause. Lifting the
3727    /// resolution rule to a typed method on the substrate primitive
3728    /// means every downstream consumer of the caixa's per-`Caixa`
3729    /// MESH-COMPOSITION outer-slice surface reaches for exactly one
3730    /// typed dispatch — the resolver's accept-set migrates as a unit on
3731    /// any future axis addition.
3732    ///
3733    /// Third outer top-level [`Caixa`] `&[Composite]`-return slice
3734    /// accessor for M2 / M3 typed-slot vec-carry axes — opens the outer-
3735    /// `Caixa` M3 mesh-slot arm of the `&[Composite]` composite-slice
3736    /// sub-family the sibling M2 [`Self::upgrade_from`] (2a1f907) /
3737    /// [`Self::children`] (c17b51e) accessors opened for the M2 vec-carry
3738    /// altitude. Peer at the outer altitude of the closed inner-
3739    /// [`crate::AplicacaoSpec::membros`] (6c77e36) accessor on the same
3740    /// MESH-COMPOSITION per-Aplicacao member-list axis — the two
3741    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3742    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3743    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3744    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3745    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3746    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3747    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3748    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3749    /// pattern onto the sibling M3 typed-composite-element axis
3750    /// ([`crate::aplicacao::Membro`] composite, matching the per-inner
3751    /// [`crate::AplicacaoSpec::membros`] element type at a different
3752    /// altitude).
3753    ///
3754    /// Returns `&[crate::aplicacao::Membro]` (not `&Vec<Membro>`)
3755    /// because every downstream consumer of the member list treats it
3756    /// as a read-only sequence — the slice-view is the narrowest borrow
3757    /// that supports every present + roadmapped consumer (`.iter()`,
3758    /// `.len()`, `.is_empty()`, the
3759    /// [`crate::aplicacao::validate_no_self_membership`] `&[Membro]`
3760    /// input, `serde` slice-serialization) without leaking the backing
3761    /// `Vec`'s grow/push/reserve surface no consumer of the typed view
3762    /// reaches for (the storage-side `Vec` remains reachable through the
3763    /// `pub membros` field for the mutation-carrying serde round-trip
3764    /// and per-test fixture-mutation paths, including the
3765    /// [`Self::aplicacao_view`] fold-in path that clones the slot into
3766    /// the typed view). Named `membros()` to match the storage field's
3767    /// name verbatim and the tatara-lisp author-surface term
3768    /// (`:membros`) the field's own docstring already carries; the
3769    /// accessor's identity maps onto the canonical MESH-COMPOSITION
3770    /// vocabulary the [`Caixa::membros`] field's docstring already
3771    /// reaches for ("Member Servicos that make up this Aplicacao").
3772    #[must_use]
3773    pub const fn membros(&self) -> &[crate::aplicacao::Membro] {
3774        self.membros.as_slice()
3775    }
3776
3777    /// Substrate-canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
3778    /// composite MESH-COMPOSITION-shaped per-Aplicacao WIT-typed
3779    /// inter-Servico contract-list slice accessor every consumer of the
3780    /// top-level manifest's per-Aplicacao `&[crate::aplicacao::WitContract]`
3781    /// slice-view keys off — returns the author-declared `:contratos`
3782    /// typed `Vec<crate::aplicacao::WitContract>` verbatim as a
3783    /// `&[crate::aplicacao::WitContract]` slice-view over the same
3784    /// backing buffer the raw `self.contratos.as_slice()` field access
3785    /// borrows from. Empty-slice-carrying (the "no contracts declared"
3786    /// arm every non-`Aplicacao`-kind `defcaixa` carries by
3787    /// `#[serde(default)]` and every leaf Aplicacao carrying only a
3788    /// single member with no inter-Servico edge carries; the returned
3789    /// `&[WitContract]` degenerates to an empty slice on those arms
3790    /// without any silent `None` collapse).
3791    ///
3792    /// The outer `:contratos` slot carries the M3 typed MESH-COMPOSITION
3793    /// per-Aplicacao WIT-typed inter-Servico edge list — the load-bearing
3794    /// container of every per-edge `{de, para, wit, endpoint | subject |
3795    /// slot}` quadruple the caixa-mesh renderer's per-Aplicacao
3796    /// `CiliumNetworkPolicy` fan-out (one L7 policy per edge —
3797    /// MESH-COMPOSITION §III.2 point 2) and per-`(:de, :para)`
3798    /// adjacency-list seed dispatch on at mesh-artifact materialization
3799    /// time (MESH-COMPOSITION §III.1 — the typed graph's edge set the
3800    /// `:membros` vertex set resolves against, closed by the
3801    /// [`crate::AplicacaoError::ContractoUnknownMember`] / cycle-refusal
3802    /// gates in §III.3; CAIXA-SDLC §II — the typed-M3 slot algebra the
3803    /// operator's per-Aplicacao fan-out dispatch fans on). Every
3804    /// per-edge axis threads through a lifted per-entry accessor on the
3805    /// [`crate::aplicacao::WitContract`] type: the peer `de` / `para`
3806    /// DNS-1123-label member-caixa-name endpoint scalar accessors, the
3807    /// [`crate::aplicacao::WitContract::endpoint`] (7020470) HTTP-shape
3808    /// / [`crate::aplicacao::WitContract::subject`] (90de675)
3809    /// NATS-pub-sub-shape / [`crate::aplicacao::WitContract::slot`]
3810    /// (ed22b66) `wasi:keyvalue/store`-shape payload-carrier accessors,
3811    /// and the WIT-world discriminant. Every downstream consumer of the
3812    /// mesh-graph edge path first passes through this outer accessor
3813    /// onto the slice and then dispatches per-contract through the
3814    /// inner accessors — the two-level dispatch means every
3815    /// per-`:contratos` reader now routes through a typed dispatch on
3816    /// the substrate primitive at both altitudes.
3817    ///
3818    /// Prior to this lift the `.contratos` `Vec<WitContract>` slot was
3819    /// accessed inline at two production sites in
3820    /// caixa-core/src/manifest.rs — the [`Self::declared_mesh_slots`]
3821    /// mesh-slot declared-slot enumerator's
3822    /// `!self.contratos.is_empty()` presence probe (which drives the
3823    /// `M3_AUTHOR_KEY_CONTRATOS` kebab-case author-label push every
3824    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-coherence
3825    /// gate reads) and the [`Self::aplicacao_view`] per-Aplicacao
3826    /// typed-view composer's `self.contratos.clone()` per-contract
3827    /// fold-in path (which materializes the typed
3828    /// [`crate::aplicacao::AplicacaoSpec`] view every
3829    /// [`crate::StandardLayout::verify`] Aplicacao-arm gate and every
3830    /// downstream `caixa-mesh` renderer dispatches on). A future
3831    /// extension of the outer `:contratos` axis (a per-cluster
3832    /// `:contratos-overrides` overlay the wasm-engine operator resolves
3833    /// at admission time so a cluster-specific edge-set can tighten a
3834    /// caixa-declared list without re-authoring the `caixa.lisp`,
3835    /// promotion of the plain `Vec<WitContract>` to a richer
3836    /// `{static, dynamic}` partition once runtime-resolved contract
3837    /// edges land, per-edge policy annotation once the M4 per-edge
3838    /// policy overlay axis lands) would have had to be threaded through
3839    /// both open-coded copies in lockstep or one consumer would
3840    /// silently disagree with the peer on which edge slice a given
3841    /// Caixa resolves to — the enumerator's presence probe reading the
3842    /// raw slot while the peer view-composer's fold-in path read an
3843    /// operator-resolved slot would silently split the paired
3844    /// declared-slot enumerator and typed-view composition, a
3845    /// two-consumer split at the enumerator and the view composer far
3846    /// from the source `caixa.lisp` with no field naming the edge-set-
3847    /// drift root cause. Lifting the resolution rule to a typed method
3848    /// on the substrate primitive means every downstream consumer of
3849    /// the caixa's per-`Caixa` MESH-COMPOSITION outer-slice surface
3850    /// reaches for exactly one typed dispatch — the resolver's
3851    /// accept-set migrates as a unit on any future axis addition.
3852    ///
3853    /// Fourth and final outer top-level [`Caixa`] `&[Composite]`-return
3854    /// slice accessor for M2 / M3 typed-slot vec-carry axes — closes
3855    /// the outer-`Caixa` `&[Composite]` composite-slice sub-family the
3856    /// sibling M2 [`Self::upgrade_from`] (2a1f907) / [`Self::children`]
3857    /// (c17b51e) accessors opened and the M3 [`Self::membros`]
3858    /// (0f26987) accessor folded on, and closes the outer-`Caixa` M3
3859    /// mesh-slot arm of the composite-slice sub-family the sibling
3860    /// [`Self::membros`] accessor opened for the M3 vec-carry altitude.
3861    /// Peer at the outer altitude of the closed inner-
3862    /// [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
3863    /// same MESH-COMPOSITION per-Aplicacao contract-list axis — the two
3864    /// altitudes now share the same "byte-equal, borrow-shared" outer-
3865    /// accessor discipline. Sibling in shape to the peer outer-`Caixa`
3866    /// `&[Dep]`-return [`Self::deps`] (ad34b4e) / [`Self::deps_dev`]
3867    /// (f7fd81e) and `&[String]`-return [`Self::autores`] (b5d813f) /
3868    /// [`Self::etiquetas`] (78c7d3c) / [`Self::bibliotecas`] (8a36c23) /
3869    /// [`Self::exe`] (65d9527) / [`Self::servicos`] (611f78b) slice-
3870    /// accessors on the sibling outer-`Caixa` scalar-element vec-carry
3871    /// axes — folds the "outer [`Caixa`] `&[T]` slice" projection
3872    /// pattern onto the sibling M3 typed-composite-element axis
3873    /// ([`crate::aplicacao::WitContract`] composite, matching the
3874    /// per-inner [`crate::AplicacaoSpec::contratos`] element type at a
3875    /// different altitude).
3876    ///
3877    /// Returns `&[crate::aplicacao::WitContract]` (not
3878    /// `&Vec<WitContract>`) because every downstream consumer of the
3879    /// contract list treats it as a read-only sequence — the slice-view
3880    /// is the narrowest borrow that supports every present + roadmapped
3881    /// consumer (`.iter()`, `.len()`, `.is_empty()`, per-edge WIT-world
3882    /// discriminant dispatch, `serde` slice-serialization) without
3883    /// leaking the backing `Vec`'s grow/push/reserve surface no
3884    /// consumer of the typed view reaches for (the storage-side `Vec`
3885    /// remains reachable through the `pub contratos` field for the
3886    /// mutation-carrying serde round-trip and per-test fixture-mutation
3887    /// paths, including the [`Self::aplicacao_view`] fold-in path that
3888    /// clones the slot into the typed view). Named `contratos()` to
3889    /// match the storage field's name verbatim and the tatara-lisp
3890    /// author-surface term (`:contratos`) the field's own docstring
3891    /// already carries; the accessor's identity maps onto the canonical
3892    /// MESH-COMPOSITION vocabulary the [`Caixa::contratos`] field's
3893    /// docstring already reaches for ("WIT-typed inter-Servico
3894    /// contracts").
3895    #[must_use]
3896    pub const fn contratos(&self) -> &[crate::aplicacao::WitContract] {
3897        self.contratos.as_slice()
3898    }
3899
3900    /// Compose the Aplicacao-related flat slots into a single typed
3901    /// [`crate::aplicacao::AplicacaoSpec`] for validation +
3902    /// downstream renderer consumption. Returns `None` when the
3903    /// caixa isn't a `:kind Aplicacao`.
3904    #[must_use]
3905    pub fn aplicacao_view(&self) -> Option<crate::aplicacao::AplicacaoSpec> {
3906        if !self.kind().is_aplicacao() {
3907            return None;
3908        }
3909        Some(crate::aplicacao::AplicacaoSpec {
3910            membros: self.membros().to_vec(),
3911            contratos: self.contratos().to_vec(),
3912            politicas: self.politicas().cloned().unwrap_or_default(),
3913            placement: self.placement().cloned().unwrap_or_default(),
3914            entrada: self.entrada().cloned(),
3915        })
3916    }
3917
3918    /// The kebab-case `:slot` tags of every M3 mesh slot this caixa
3919    /// *declares* a value on, in canonical declaration order
3920    /// (`:membros` → `:contratos` → `:politicas` → `:placement` →
3921    /// `:entrada`). A slot counts as declared when its backing field
3922    /// carries a value — a non-empty `Vec`, or a `Some(...)`.
3923    ///
3924    /// The M3 mesh slots compose the typed graph of a `:kind Aplicacao`
3925    /// (MESH-COMPOSITION §III.1). [`Self::aplicacao_view`] only folds
3926    /// them into a validatable [`crate::aplicacao::AplicacaoSpec`] when
3927    /// the kind matches (returns `None` otherwise), and the caixa-mesh /
3928    /// caixa-flux / caixa-helm renderers only emit them for an
3929    /// Aplicacao. On any *other* kind a declared mesh slot is the
3930    /// manifest field's documented "ignored otherwise" (see the
3931    /// `:membros` … `:entrada` field docs): it silently passes
3932    /// [`Caixa::from_lisp`] and then vanishes — never validated, never
3933    /// rendered — far from the source caixa.lisp.
3934    /// [`crate::StandardLayout::verify`] consults this to reject that
3935    /// silent-drop at caixa-build time
3936    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]), mirroring the
3937    /// `SupervisorOwnsCode` / `AplicacaoOwnsCode` kind-coherence gates:
3938    /// a slot foreign to the kind is a build error, not a silent drop.
3939    ///
3940    /// Lifted as a typed method (rather than an inline disjunction at
3941    /// the verify call site) so the mesh-slot set lives in one place —
3942    /// a future M4 axis added to the Aplicacao surface (per-edge policy
3943    /// overlay, distributed-app takeover config) is one push here, and
3944    /// every consumer reaching for "which mesh slots are set" (the
3945    /// verify gate, a future `feira lint` kind-coherence advisory)
3946    /// inherits the canonical order without rolling its own.
3947    ///
3948    /// Each per-arm kebab-case label is routed through the peer
3949    /// [`crate::M3_AUTHOR_KEY_MEMBROS`] /
3950    /// [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
3951    /// [`crate::M3_AUTHOR_KEY_POLITICAS`] /
3952    /// [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
3953    /// [`crate::M3_AUTHOR_KEY_ENTRADA`] consts declared next to the
3954    /// [`crate::M3_KEY_PLACEMENT`] renderer-side wire-key peer, so both
3955    /// halves of every M3 top-level mesh slot's dual axis (author-facing
3956    /// kebab-case label + renderer-side artifact key) route through one
3957    /// canonical declaration per arm — same discipline the peer
3958    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`]
3959    /// / [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot consts
3960    /// (f49c8b0) establish on the sibling per-Servico M2 top-level slot
3961    /// axis, extended here to close the M3 mesh-slot author-facing-label
3962    /// axis so both altitudes of the typed-slot algebra
3963    /// (per-Servico M2 + per-Aplicacao M3) share the same
3964    /// "one canonical byte-string per arm, next to the axis" discipline.
3965    #[must_use]
3966    pub fn declared_mesh_slots(&self) -> Vec<&'static str> {
3967        let mut slots = Vec::new();
3968        if !self.membros().is_empty() {
3969            slots.push(crate::render::M3_AUTHOR_KEY_MEMBROS);
3970        }
3971        if !self.contratos().is_empty() {
3972            slots.push(crate::render::M3_AUTHOR_KEY_CONTRATOS);
3973        }
3974        if self.politicas().is_some() {
3975            slots.push(crate::render::M3_AUTHOR_KEY_POLITICAS);
3976        }
3977        if self.placement().is_some() {
3978            slots.push(crate::render::M3_AUTHOR_KEY_PLACEMENT);
3979        }
3980        if self.entrada().is_some() {
3981            slots.push(crate::render::M3_AUTHOR_KEY_ENTRADA);
3982        }
3983        slots
3984    }
3985
3986    /// The kebab-case `:slot` tags of every supervisor-tree slot this
3987    /// caixa *declares* a value on, in canonical declaration order
3988    /// (`:estrategia` → `:max-restarts` → `:restart-window` →
3989    /// `:children`). A slot counts as declared when its backing field
3990    /// carries a value — a `Some(...)`, or a non-empty `Vec`.
3991    ///
3992    /// The supervisor-tree slots compose the typed OTP supervisor of a
3993    /// `:kind Supervisor` (INSPIRATIONS §II.2; the `:estrategia` +
3994    /// `:children` field docs above). [`Self::supervisor_view`] only
3995    /// folds them into a validatable [`SupervisorSpec`] when the kind
3996    /// matches (returns `None` otherwise), and the wasm-operator's
3997    /// hierarchical reconciler only consumes them for a Supervisor. On
3998    /// any *other* kind a declared supervisor slot is the manifest
3999    /// field's documented "ignored otherwise" (see the `:estrategia` …
4000    /// `:children` field docs): it silently passes [`Caixa::from_lisp`]
4001    /// and then vanishes — never validated, never reconciled — far from
4002    /// the source caixa.lisp. [`crate::StandardLayout::verify`] consults
4003    /// this to reject that silent-drop at caixa-build time
4004    /// ([`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]), the
4005    /// exact mirror of the [`Self::declared_mesh_slots`] /
4006    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] gate on the
4007    /// Aplicacao-only slot set: a slot foreign to the kind is a build
4008    /// error, not a silent drop.
4009    #[must_use]
4010    pub fn declared_supervisor_slots(&self) -> Vec<&'static str> {
4011        let mut slots = Vec::new();
4012        if self.estrategia().is_some() {
4013            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA);
4014        }
4015        if self.max_restarts().is_some() {
4016            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS);
4017        }
4018        if self.restart_window().is_some() {
4019            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW);
4020        }
4021        if !self.children().is_empty() {
4022            slots.push(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN);
4023        }
4024        slots
4025    }
4026
4027    /// The kebab-case `:slot` tags of every M2 Servico-runtime slot this
4028    /// caixa *declares* a value on, in canonical declaration order
4029    /// (`:limits` → `:behavior` → `:upgrade-from`). A slot counts as
4030    /// declared when its backing field carries a value — a `Some(...)`,
4031    /// or a non-empty `Vec`.
4032    ///
4033    /// The M2 slots configure the runtime of a long-running wasm
4034    /// component, i.e. a `:kind Servico`: `:limits` is Lunatic
4035    /// per-process sandboxing (INSPIRATIONS §III.1), `:behavior` is the
4036    /// OTP `gen_server` callback set (§II.3), `:upgrade-from` is the OTP
4037    /// appup hot-code-reload table (§II.4). The caixa-helm / caixa-flux
4038    /// renderers gate on [`crate::require_kind`]`(_, Servico)` and only
4039    /// emit these slots for a Servico; on any *other* kind a declared M2
4040    /// slot is the manifest field's documented "ignored otherwise": its
4041    /// well-formedness is checked by [`crate::StandardLayout::verify`]
4042    /// but the value is never rendered into a chart / programs.yaml entry
4043    /// — it silently passes [`Caixa::from_lisp`] + `feira build` and then
4044    /// vanishes, far from the source caixa.lisp.
4045    /// [`crate::StandardLayout::verify`] consults this to reject that
4046    /// silent-drop at caixa-build time
4047    /// ([`crate::LayoutError::ServicoSlotsOnNonServico`]), the exact
4048    /// mirror of the [`Self::declared_mesh_slots`] /
4049    /// [`Self::declared_supervisor_slots`] gates on the peer
4050    /// kind-exclusive slot sets: a slot foreign to the kind is a build
4051    /// error, not a silent drop.
4052    ///
4053    /// Each per-arm kebab-case label is routed through the peer
4054    /// [`crate::M2_AUTHOR_KEY_LIMITS`] / [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
4055    /// [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts declared next to the
4056    /// [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
4057    /// [`crate::M2_KEY_UPGRADE_FROM`] renderer-side wire-key peers, so
4058    /// both halves of the M2 top-level slot's dual axis (author-facing
4059    /// kebab-case label + renderer-side camelCase overlay-container wire
4060    /// key) route through one canonical declaration per arm — same
4061    /// discipline the peer [`crate::M2_BEHAVIOR_AUTHOR_KEY_ON_*`] sub-slot
4062    /// author-label consts (889dc18) establish on the sibling
4063    /// per-callback axis inside the `:behavior` overlay block.
4064    #[must_use]
4065    pub fn declared_servico_slots(&self) -> Vec<&'static str> {
4066        let mut slots = Vec::new();
4067        if self.limits().is_some() {
4068            slots.push(crate::render::M2_AUTHOR_KEY_LIMITS);
4069        }
4070        if self.behavior().is_some() {
4071            slots.push(crate::render::M2_AUTHOR_KEY_BEHAVIOR);
4072        }
4073        if !self.upgrade_from().is_empty() {
4074            slots.push(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM);
4075        }
4076        slots
4077    }
4078
4079    /// The kebab-case `:slot` tags of every code-surface slot this caixa
4080    /// declares a value on that its [`CaixaKind`] doesn't natively own,
4081    /// in canonical declaration order (`:exe` → `:servicos`). A
4082    /// code-surface slot is owned by exactly one kind: `:exe` by
4083    /// [`CaixaKind::Binario`] (the nix-built executable surface), and
4084    /// `:servicos` by [`CaixaKind::Servico`] (the wasm component +
4085    /// `ComputeUnit` daemon surface).
4086    ///
4087    /// Each is silently ignored when declared on the wrong kind: the
4088    /// caixa-helm / caixa-flux / caixa-flake renderers gate on
4089    /// [`crate::require_kind`]`(_, <owning-kind>)`, so on any *other*
4090    /// code-running kind a declared `:exe` / `:servicos` is the manifest
4091    /// field's documented "ignored otherwise" — its path is checked for
4092    /// existence by the layout's `bibliotecas`/`exe`/`servicos` loops
4093    /// (which run after [`Caixa::from_lisp`]), but the value is never
4094    /// rendered into a build target or programs.yaml entry. It silently
4095    /// passes [`Caixa::from_lisp`] + `feira build`, far from the source
4096    /// caixa.lisp, with no field naming which slot is foreign.
4097    ///
4098    /// [`crate::StandardLayout::verify`] consults this to reject that
4099    /// silent-drop at caixa-build time
4100    /// ([`crate::LayoutError::ForeignCodeSlot`]), beside the M2
4101    /// servico-runtime, supervisor-tree, and M3 mesh kind-coherence
4102    /// gates ([`Self::declared_servico_slots`] /
4103    /// [`Self::declared_supervisor_slots`] /
4104    /// [`Self::declared_mesh_slots`]): the fourth kind ↔ slot algebra
4105    /// axis to be closed on the typed surface. The Supervisor /
4106    /// Aplicacao "no code at all" cases ([`crate::LayoutError::SupervisorOwnsCode`]
4107    /// / [`crate::LayoutError::AplicacaoOwnsCode`]) keep their dedicated
4108    /// diagnostics — they fire ahead of this gate on the same `verify`
4109    /// pass, so for Supervisor / Aplicacao the `OwnCode` arm always wins
4110    /// and this method is moot. For Biblioteca / Binario / Servico, this
4111    /// gate fires when a code-running kind declares another code-running
4112    /// kind's exclusive code surface.
4113    ///
4114    /// `:bibliotecas` is deliberately excluded — a Binario or Servico
4115    /// may legitimately ship a `lib/` helper that the underlying
4116    /// substrate (the nix flake for Binario, the wasm component build
4117    /// for Servico) bundles into its build, so the slot's
4118    /// declared-on-wrong-kind cardinality isn't a structural error on
4119    /// either code-running kind. A Biblioteca declaring `:bibliotecas`
4120    /// is the native case (the slot's owning kind). Supervisor /
4121    /// Aplicacao declaring `:bibliotecas` is gated upstream by
4122    /// [`crate::LayoutError::SupervisorOwnsCode`] /
4123    /// [`crate::LayoutError::AplicacaoOwnsCode`].
4124    ///
4125    /// Lifted as a typed method (rather than an inline disjunction at
4126    /// the verify call site) so the foreign-code-slot set lives in one
4127    /// place — a future kind that gains its own code-surface slot is
4128    /// one push here, and every consumer reaching for "which code
4129    /// surfaces are foreign to this kind" (the verify gate, a future
4130    /// `feira lint` kind-coherence advisory, the future `app-operator`'s
4131    /// per-caixa build-target classifier) inherits the canonical order
4132    /// without rolling its own.
4133    #[must_use]
4134    pub fn declared_foreign_code_slots(&self) -> Vec<&'static str> {
4135        let mut slots = Vec::new();
4136        if !self.exe().is_empty() && !self.kind().requires_exe() {
4137            slots.push(":exe");
4138        }
4139        if !self.servicos().is_empty() && !self.kind().requires_servicos() {
4140            slots.push(":servicos");
4141        }
4142        slots
4143    }
4144
4145    /// Validate every entry of `:deps` and `:deps-dev` through
4146    /// [`Dep::validate`] — closing the parity loop with the per-axis
4147    /// `:versao` gates already wired into the typed-graph
4148    /// ([`crate::AplicacaoSpec::validate_membros`] for `:membros`,
4149    /// 9888b13) and typed supervisor tree
4150    /// ([`crate::SupervisorSpec::validate`] for `:children`, b38ff3a).
4151    ///
4152    /// Until this gate landed `:deps :versao` and `:deps-dev :versao`
4153    /// were the only `:versao` axes still untyped past
4154    /// [`Caixa::from_lisp`]: the derive macro stored the requirement
4155    /// as a String without parsing it, so a malformed-but-non-empty
4156    /// requirement (`"^bad-version"`, `"^^0.1"`, `"v0.1"`, `"not-a-req"`)
4157    /// silently passed parse and the `semver::Error` surfaced at
4158    /// lacre-resolve time, far from the source caixa.lisp, with no
4159    /// field naming which `:deps` entry carried the typo. Lifting the
4160    /// gate here makes the four `:versao` typed surfaces (`:deps`,
4161    /// `:deps-dev`, `:membros`, `:children`) structurally equivalent —
4162    /// every requirement string past `validate_deps` is round-trippable
4163    /// through [`crate::parse_requirement`] without re-checking at the
4164    /// resolver layer.
4165    ///
4166    /// Both lists run through the same per-entry validator so a typo
4167    /// in `:deps-dev` surfaces with the same diagnostic as one in
4168    /// `:deps` — neither axis is a second-class citizen of the typed
4169    /// surface.
4170    ///
4171    /// Within each list, [`DepError::DuplicateNome`] closes the
4172    /// set-not-multiset discipline on the `:nome` axis: two entries
4173    /// naming the same caixa carry two `:versao` / `:fonte` / feature
4174    /// triples that the caixa-resolver's lacre pipeline collapses to one
4175    /// via its `HashMap`-keyed-by-`:nome` consumption — the second entry
4176    /// silently overwrites the first at `concrete_versao`-resolve time
4177    /// (the same "second wins / one silently overwrites the other"
4178    /// shape the peer typed-graph duplicate gates already close on every
4179    /// other Vec-shaped authoring surface that keys by name). The
4180    /// duplicate check fires per-list and runs *after* each per-entry
4181    /// [`Dep::validate`] call so a malformed-and-duplicated entry
4182    /// surfaces its narrower per-entry diagnostic
4183    /// ([`DepError::NomeInvalid`], [`DepError::VersaoInvalid`],
4184    /// [`DepError::FonteRepoEmpty`], …) before the cross-entry duplicate
4185    /// diagnostic — the canonical "per-entry shape before cross-entry
4186    /// uniqueness" precedence the peer `:children :caixa`
4187    /// ([`crate::SupervisorSpec::validate`]), `:membros :caixa`
4188    /// ([`crate::AplicacaoSpec::validate_membros`]), `:contratos`
4189    /// ([`crate::AplicacaoSpec::validate`]), `:placement :clusters`
4190    /// ([`crate::AplicacaoSpec::validate_placement`]),
4191    /// `:entrada :paths` ([`crate::AplicacaoSpec::validate`]),
4192    /// `:upgrade-from :from` ([`crate::upgrade::validate_upgrade_from`]),
4193    /// and the within-`:upgrade-from`-entry per-instruction-class
4194    /// singularity gates ([`crate::UpgradeError::DuplicateLoadModule`],
4195    /// [`crate::UpgradeError::DuplicateStateChange`],
4196    /// [`crate::UpgradeError::DuplicateCleanup`]) all establish.
4197    ///
4198    /// Cross-list (`:deps` ↔ `:deps-dev`) coincidence is *not* gated
4199    /// here: Cargo's `[dependencies]` + `[dev-dependencies]` accept the
4200    /// same name in both tables (the dev table's pin overrides the
4201    /// runtime table's pin in test/dev contexts), and caixa's surface
4202    /// mirrors that convention until a deliberate choice retires the
4203    /// override pattern. Only within-list duplicates are structurally
4204    /// incoherent — those are what this gate closes.
4205    ///
4206    /// Compound per-`Caixa` entry gate on the dep-graph axis: folds the
4207    /// two standalone dep-list validators — the per-entry + within-list
4208    /// duplicate-`:nome` walk (the [`Dep::validate`] +
4209    /// [`crate::render::insert_first_seen`] cascade this method opened
4210    /// on) and the cross-slot self-edge gate
4211    /// ([`crate::dep::validate_no_self_dep`]) — onto one substrate
4212    /// primitive on [`Caixa`]. The two arms run in the same canonical
4213    /// order the layout pipeline
4214    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4215    /// author-time gate) has always sequenced them (per-entry +
4216    /// cross-entry duplicate → cross-slot self-edge), so the fold is
4217    /// byte-for-byte equivalent to the pre-fold two-block cascade at
4218    /// that call site (pinned by the paired
4219    /// `validate_deps_folds_per_entry_arm_matches_gate` /
4220    /// `validate_deps_folds_self_edge_arm_matches_gate` equivalence
4221    /// pins and the `validate_deps_per_entry_arm_fires_before_self_edge_arm`
4222    /// ordering pin). Self-contained on `&self` — resolves its three
4223    /// inputs ([`Self::deps`], [`Self::deps_dev`], [`Self::nome`])
4224    /// through the substrate primitives' own accessor family, the same
4225    /// posture every peer per-slot compound gate
4226    /// ([`crate::AplicacaoSpec::validate_contratos`],
4227    /// [`crate::MeshPolicy::validate`],
4228    /// [`crate::SupervisorSpec::validate_children`],
4229    /// [`Self::validate_upgrade_from`]) already carries.
4230    ///
4231    /// Prior to this lift [`crate::dep::validate_no_self_dep`] lived
4232    /// only open-coded at the layout wire-up site
4233    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs)
4234    /// as a standalone two-arg dispatch immediately after this method's
4235    /// per-entry + cross-entry walk, both wrapped through the same
4236    /// [`crate::LayoutError::DepsViolation`] envelope: every future
4237    /// consumer that wanted to gate the dep-graph as a whole — the
4238    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4239    /// per-CR admission webhook re-checking `:deps` / `:deps-dev` after
4240    /// a per-entry patch, a future `feira validate --deps` per-caixa
4241    /// admission verb, a per-`:deps` overlay resolver a per-cluster
4242    /// overlay lift would materialize (each the deferred consumer this
4243    /// method's peer [`Self::deps`] / [`Self::deps_dev`] accessors'
4244    /// docstrings already name) — was structurally forced to either
4245    /// re-inline the two-dispatch cascade in lockstep with the layout
4246    /// wire-up (the duplication the PRIME DIRECTIVE names as a bug) or
4247    /// call the whole [`crate::layout::StandardLayout::verify`] pipeline
4248    /// and pay every peer per-Caixa gate to re-check one slot. Post-fold
4249    /// each such consumer reaches the two-arm compound gate through one
4250    /// call on the substrate primitive.
4251    pub fn validate_deps(&self) -> Result<(), DepError> {
4252        for &list in crate::dep::DepList::ALL {
4253            let mut seen = std::collections::HashSet::new();
4254            for dep in self.deps_of(list) {
4255                dep.validate()?;
4256                crate::render::insert_first_seen(&mut seen, dep.nome(), || {
4257                    DepError::duplicate_nome(dep.nome(), list.as_str())
4258                })?;
4259            }
4260        }
4261        crate::dep::validate_no_self_dep(self.deps(), self.deps_dev(), self.nome())?;
4262        Ok(())
4263    }
4264
4265    /// Run a per-slot typed validator on `self` and, on the per-arm
4266    /// parser-side error arm, thread the error into a paired
4267    /// [`crate::LayoutError`] wrap under `self.nome()`. Substrate
4268    /// primitive folding the 18 self-similar layout-pipeline wire-up
4269    /// sites at [`crate::layout::StandardLayout::verify`] that carry
4270    /// the identical
4271    /// `caixa.validate_<slot>().map_err(|err| crate::LayoutError::<slot>_violation(caixa, err))?;`
4272    /// cascade onto one dispatch. Each of the eighteen sites (`:nome`,
4273    /// `:nome`-chart-name-budget, `:versao`, `:deps`, `:etiquetas`,
4274    /// `:autores`, `:repositorio`, `:descricao`, `:licenca`, `:edicao`,
4275    /// `:bibliotecas`/`:exe`/`:servicos` code-path shape, `:limits`,
4276    /// `:behavior`, `:upgrade-from`, `:restart-window`, per-Supervisor
4277    /// shape, per-Aplicacao shape, per-Acao shape) carried the same
4278    /// four-line "run a per-slot typed validator on `caixa` and, on the
4279    /// per-arm parser-side error arm, thread it into the paired
4280    /// [`crate::LayoutError`] one-slot envelope through the substrate-
4281    /// canonical `layout_violation_ctors!` family (131ca0d)" cascade,
4282    /// differing only in the two names bound at each site — the
4283    /// validator (`Caixa::validate_deps` / `validate_nome` / ...) and
4284    /// the paired ctor (`LayoutError::deps_violation` / ...). Eighteen
4285    /// consumers, one identical shape, one substrate primitive on
4286    /// [`Caixa`] closing the duplication the PRIME DIRECTIVE names as
4287    /// a bug — on the second half of the per-slot cascade the peer
4288    /// substrate primitives on the [`crate::LayoutError`]-wrap side
4289    /// (the `layout_violation_ctors!` macro 131ca0d, the
4290    /// `layout_slot_kind_ctors!` macro 0419438, the `layout_nome_only_ctors!`
4291    /// macro 3fe3dd7, the [`crate::LayoutError::missing_entry`] ctor
4292    /// 1b09f9d, the [`crate::layout::StandardLayout::probe_declared_entry`]
4293    /// primitive fda1e35) each closed on their sibling envelopes; the
4294    /// first half of the cascade (the per-slot compound gates
4295    /// [`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
4296    /// baa4688, [`Self::validate_behavior`] 0d2877a,
4297    /// [`Self::validate_upgrade_from`] d6801df,
4298    /// [`Self::validate_aplicacao_shape`] 949a7a0,
4299    /// [`Self::validate_supervisor_shape`] 4c70105,
4300    /// [`Self::validate_acao_shape`] 5d6df54,
4301    /// [`Self::validate_kind_slot_coherence`] f0d286e,
4302    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
4303    /// [`Self::validate_ci_kind_coherence`] 9b55beb,
4304    /// [`Self::validate_required_kind_slot`] 9c385d8) each closed on
4305    /// their per-slot compound gates.
4306    ///
4307    /// Composes the [`crate::layout::LayoutError`] wrap and the per-slot
4308    /// typed validator through two typed callables: `gate` runs on
4309    /// `self` and yields a per-slot error `E`; on the `Err(E)` arm
4310    /// `wrap` re-wraps that error under `self` into a
4311    /// [`crate::layout::LayoutError`]. The `Ok(())` arm passes through
4312    /// verbatim as the fold's identity element — byte-equal to the
4313    /// pre-lift `Result::map_err` short-circuit at the `?;` marker
4314    /// every wire-up site formerly carried. Every future consumer that
4315    /// wants to run one of the per-slot gates and thread its error
4316    /// through the layout wrap (the deferred
4317    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission-
4318    /// webhook per-slot re-check, a future `feira validate --<slot>`
4319    /// per-caixa admission verb, an overlay resolver re-running one
4320    /// gate after a per-slot patch) reaches the two-callable dispatch
4321    /// through one call rather than re-inlining the four-line cascade
4322    /// in lockstep with the pre-existing 18 wire-ups. The two callables
4323    /// reach the primitive as first-class type-checked references
4324    /// rather than the pre-lift `.map_err(|err| CTOR(caixa, err))`
4325    /// closure body — so a mismatch between the validator's `E` type
4326    /// and the ctor's `E` bound trips at the wire-up site (compile-
4327    /// time) rather than at the closure body (also compile-time, but
4328    /// with a diagnostic pointing at the closure expression rather
4329    /// than the two named callables).
4330    pub fn run_layout_gate<E, W>(
4331        &self,
4332        gate: impl FnOnce(&Caixa) -> Result<(), E>,
4333        wrap: W,
4334    ) -> Result<(), crate::LayoutError>
4335    where
4336        W: FnOnce(&Caixa, E) -> crate::LayoutError,
4337    {
4338        gate(self).map_err(|err| wrap(self, err))
4339    }
4340
4341    /// Run one arm of the cross-family kind ↔ owned-slot-family
4342    /// coherence cascade on `self`: on a caixa whose [`Self::kind`] does
4343    /// not own the typed-slot family named by `is_owner`, refuse when
4344    /// the paired `accumulator` reports any declared slot in that
4345    /// family; otherwise pass. Substrate primitive folding the three
4346    /// self-similar four-line
4347    /// `if !self.kind().is_<owner>() { let slots = self.declared_<family>_slots();
4348    /// if !slots.is_empty() { return Err(<wrap>(self, slots)); } }`
4349    /// arms at [`Self::validate_kind_slot_coherence`] onto one dispatch.
4350    /// Three consumers (M3 mesh — Aplicacao-owner, supervisor-tree —
4351    /// Supervisor-owner, M2 Servico-runtime — Servico-owner), one
4352    /// identical shape, one substrate primitive on [`Caixa`] closing
4353    /// the duplication the PRIME DIRECTIVE names as a bug on the
4354    /// outer kind-coherence arm shape — peer with the substrate
4355    /// primitives on the two adjacent halves of the same three-arm
4356    /// cascade the sibling [`Self::declared_mesh_slots`] /
4357    /// [`Self::declared_supervisor_slots`] /
4358    /// [`Self::declared_servico_slots`] accumulator family closes on
4359    /// the inner slot-set enumerator axis and the sibling
4360    /// [`crate::layout::layout_slot_kind_ctors!`] macro (0419438)
4361    /// closes on the inner wrap-envelope ctor axis. Each of the three
4362    /// [`Self::validate_kind_slot_coherence`] arms now reads through
4363    /// one call across every altitude of the per-arm cascade:
4364    /// one dispatch on this primitive for the outer guard shape, one
4365    /// dispatch on `Self::declared_<family>_slots` for the accumulator,
4366    /// one dispatch on `crate::LayoutError::<family>_on_non_<owner>`
4367    /// for the wrap ctor.
4368    ///
4369    /// Composes the outer owner-kind guard, the per-family accumulator,
4370    /// and the per-family wrap ctor through three typed callables:
4371    /// `is_owner` runs on `&self.kind()` (a `&CaixaKind` borrow so the
4372    /// `gen_platform::IsVariant`-derived `fn(&CaixaKind) -> bool`
4373    /// per-arm predicates — [`crate::CaixaKind::is_aplicacao`] /
4374    /// [`crate::CaixaKind::is_supervisor`] / [`crate::CaixaKind::is_servico`]
4375    /// — pass verbatim as function references), `accumulator` runs on
4376    /// `&self` and yields the
4377    /// per-family declared-slot list, and `wrap` runs on `(&self,
4378    /// Vec<&'static str>)` and yields the per-family
4379    /// [`crate::LayoutError`] wrap. The `is_owner` short-circuit fires
4380    /// before the accumulator dispatch (so the owner kind of each
4381    /// family passes without invoking `accumulator`, byte-equal to the
4382    /// pre-lift `if !self.kind().is_<owner>() { … }` outer guard's
4383    /// short-circuit — pinned by
4384    /// `run_kind_owned_slot_family_gate_owner_kind_short_circuits_before_accumulator`),
4385    /// and the accumulator's `is_empty` short-circuit fires before the
4386    /// wrap dispatch (so a non-owner kind with no declared slot in that
4387    /// family passes without invoking `wrap`, byte-equal to the pre-lift
4388    /// `if !<slots>.is_empty() { … }` inner guard's short-circuit —
4389    /// pinned by
4390    /// `run_kind_owned_slot_family_gate_empty_accumulator_short_circuits_before_wrap`).
4391    /// The wrap ctor is `FnOnce(&Caixa, Vec<&'static str>) ->
4392    /// crate::LayoutError` — matching the [`crate::layout::layout_slot_kind_ctors!`]
4393    /// macro's per-variant `fn(&Caixa, Vec<&'static str>) -> LayoutError`
4394    /// substrate-canonical ctor shape verbatim, so
4395    /// [`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
4396    /// [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
4397    /// [`crate::LayoutError::servico_slots_on_non_servico`] pass as
4398    /// function references without a closure wrap. A mismatch between
4399    /// the ctor's signature and this bound trips at the wire-up site
4400    /// (compile-time) rather than at a closure body.
4401    ///
4402    /// The sibling [`crate::LayoutError::ForeignCodeSlot`] gate on the
4403    /// code-surface family sits outside this primitive because
4404    /// [`Self::declared_foreign_code_slots`] bakes the per-arm kind-
4405    /// check into the accumulator itself (each arm's
4406    /// `!self.kind().requires_<slot>()` guard fires inside the
4407    /// accumulator, not around it), so the code-surface arm carries no
4408    /// outer `is_owner`-shaped guard and its dispatch reads through
4409    /// [`Self::validate_foreign_code_kind_coherence`] verbatim without
4410    /// this primitive — the same posture the `_no_code_` /
4411    /// `_ci_kind_` coherence axes take on their respective per-arm
4412    /// shapes. The primitive here is specific to the "outer
4413    /// non-owner-kind guard + inner accumulator + inner emptiness
4414    /// guard + wrap" arm shape that fires three times in
4415    /// [`Self::validate_kind_slot_coherence`].
4416    ///
4417    /// Every future consumer that wants to gate one kind-owned slot
4418    /// family as a unit outside the composed cascade (the deferred
4419    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission-
4420    /// webhook per-family re-check after a per-slot patch, a future
4421    /// `feira validate --<family>-coherence` per-caixa admission verb,
4422    /// a per-`Caixa` overlay resolver rejecting a kind-foreign patch
4423    /// on one family) reaches the four-line arm through one call
4424    /// rather than re-inlining the outer-guard + accumulator +
4425    /// emptiness-guard + wrap cascade in lockstep with the pre-existing
4426    /// three arms. Every future kind-owned typed-slot family (an
4427    /// `Actor`-owned per-virtual-actor grain slot the M5 Orleans-
4428    /// inspired kind reaches through, a per-Aplicacao overlay slot the
4429    /// M4 CR materializer consults) folds onto
4430    /// [`Self::validate_kind_slot_coherence`] as one additional
4431    /// dispatch on this primitive rather than a fourth open-coded
4432    /// four-line block.
4433    pub fn run_kind_owned_slot_family_gate<F, A, W>(
4434        &self,
4435        is_owner: F,
4436        accumulator: A,
4437        wrap: W,
4438    ) -> Result<(), crate::LayoutError>
4439    where
4440        F: FnOnce(&crate::CaixaKind) -> bool,
4441        A: FnOnce(&Caixa) -> Vec<&'static str>,
4442        W: FnOnce(&Caixa, Vec<&'static str>) -> crate::LayoutError,
4443    {
4444        if is_owner(&self.kind()) {
4445            return Ok(());
4446        }
4447        let slots = accumulator(self);
4448        if slots.is_empty() {
4449            return Ok(());
4450        }
4451        Err(wrap(self, slots))
4452    }
4453
4454    /// Reject `:nome` values the K8s apiserver would refuse at admission
4455    /// time. The top-level Caixa identity flows directly into every
4456    /// substrate-side artifact's `metadata.name` axis: the
4457    /// `lareira-<nome>` Helm chart name ([`caixa-helm::lib::chart_name`]),
4458    /// the programs.yaml `name:` entry the `lareira-fleet-programs`
4459    /// aggregator keys ComputeUnit derivation off
4460    /// ([`caixa-flux::lib::programs_yaml_entry`]), the
4461    /// `LABEL_APLICACAO` label value carried on every Aplicacao-owned
4462    /// pod and the per-`:contratos` CiliumNetworkPolicy `metadata.name`
4463    /// (`<aplicacao>-<de>-to-<para>`) and the per-`:entrada`
4464    /// `<aplicacao>-<para>` HTTPRoute `metadata.name`
4465    /// ([`caixa-mesh::lib::cilium_network_policies`],
4466    /// [`caixa-mesh::lib::gateway_routes`]), and the default
4467    /// `lib/<nome>.lisp` / `exe/<nome>` layout paths
4468    /// ([`crate::StandardLayout::verify`]). Each K8s apiserver-side
4469    /// schema enforces the DNS-1123 label rule on admission; a
4470    /// structurally invalid `:nome` (`"MyApp"` — the canonical
4471    /// "I copied the display name verbatim" footgun, `"my_app"` — the
4472    /// Python-/Postgres-leak, `"team.app"` — `:nome` is a single label
4473    /// not a subdomain, `"-app"` / `"app-"` — DNS-1123 boundary
4474    /// violations, `"my app"` — the paste-from-doc footgun, `"café"` —
4475    /// IDN must be pre-encoded as Punycode, the 64-byte UUID-shaped
4476    /// over-cap slug) silently passed [`Caixa::from_lisp`] and the
4477    /// failure surfaced at `kubectl apply` time as a `metadata.name:
4478    /// Invalid value` rejection on whichever derived artifact admitted
4479    /// first, far from the source `caixa.lisp` and without any field
4480    /// naming the offending `:nome`.
4481    ///
4482    /// Thin wrapper around [`crate::render::is_dns_1123_label`] (the
4483    /// substrate-side predicate the per-axis name gates already share:
4484    /// `:membros :caixa` 3f9d7a0, `:placement :clusters` 6cbb900,
4485    /// `:children :caixa` 31bfa43) that maps the shared parser-shaped
4486    /// reason into the [`ManifestError::NomeInvalid`] variant, so the
4487    /// diagnostic is self-locating (the offending `:nome` is named
4488    /// verbatim) and the author can grep their `caixa.lisp` for
4489    /// `:nome "<value>"` and fix it in one edit. Same diagnostic shape
4490    /// every per-axis sibling gate already exposes
4491    /// ([`crate::AplicacaoError::MembroCaixaInvalid`],
4492    /// [`crate::AplicacaoError::PlacementClusterInvalid`],
4493    /// [`crate::SupervisorError::ChildCaixaInvalid`]).
4494    ///
4495    /// Empty `:nome` (which [`Caixa::from_lisp`] does not reject — the
4496    /// derive macro stores the raw String) is gated by the narrower
4497    /// [`ManifestError::NomeEmpty`] arm before the predicate is
4498    /// consulted, mirroring the empty-first cascade every per-axis
4499    /// name gate already uses (e.g. `MembroCaixaEmpty` before
4500    /// `MembroCaixaInvalid`, `EmptyChildName` before `ChildCaixaInvalid`).
4501    pub fn validate_nome(&self) -> Result<(), ManifestError> {
4502        // Routes through the shared
4503        // [`crate::render::require_valid_dns_1123_label`] gate the peer
4504        // name axes each land on so drift between the eight axes'
4505        // accepted DNS-1123-label sets is structurally impossible.
4506        let nome = self.nome();
4507        crate::render::require_valid_dns_1123_label(
4508            nome,
4509            || ManifestError::NomeEmpty,
4510            |reason| ManifestError::nome_invalid(nome, reason),
4511        )
4512    }
4513
4514    /// Reject `:nome` values whose joint length with the canonical
4515    /// [`crate::LAREIRA_CHART_NAME_PREFIX`] (`"lareira-"`) overflows
4516    /// the K8s DNS-1123 label cap [`crate::DNS_1123_LABEL_MAX_LEN`]
4517    /// (63 bytes). Every per-Servico / per-Aplicacao renderer the
4518    /// substrate carries materializes the caixa's `:nome` through the
4519    /// canonical [`crate::lareira_chart_name`] helper (f7320d7) into a
4520    /// `lareira-<nome>` artifact that lands as a K8s `metadata.name` /
4521    /// Helm chart name / `HelmRelease` `release_name`: `caixa-helm`'s
4522    /// `ChartDir.name` + `Chart.yaml::name`
4523    /// (caixa-helm/src/lib.rs:207), `caixa-flux`'s `cluster_bundle`
4524    /// `HelmRelease` `chart:` slot (caixa-flux/src/lib.rs:329),
4525    /// `caixa-tatara`'s `process_for_aplicacao` `release_name` +
4526    /// `oci://<registry>/lareira-<nome>` chart ref
4527    /// (caixa-tatara/src/lib.rs:124,178). Helm's own `Chart.yaml::name`
4528    /// admission rule strict-parses against DNS-1123-label, the Helm
4529    /// operator's tracking-secret name is derived from `release_name`
4530    /// and is itself DNS-1123-label-bounded, and the rendered chart's
4531    /// K8s object `metadata.name` axes embed the chart name as a
4532    /// prefix — every one fails admission on a > 63-byte chart name.
4533    ///
4534    /// The per-axis [`Self::validate_nome`] gate (6c992f8) already
4535    /// caps `:nome` itself at 63 bytes via [`is_dns_1123_label`], so a
4536    /// `:nome` of 56–63 bytes silently passed validate (the inner
4537    /// DNS-1123 check accepts the bare `:nome`) but produced a
4538    /// `lareira-<nome>` of 64–71 bytes that the apiserver / `helm lint`
4539    /// rejected at admission — far from the source `caixa.lisp`, with
4540    /// no field naming the overflow root cause. The
4541    /// [`lareira_chart_name`] helper's own doc comment
4542    /// (caixa-core/src/render.rs:3198) explicitly deferred the fix:
4543    /// "the M4 admission webhook will pin the joint-length invariant
4544    /// when it lands". This gate lands the invariant at the
4545    /// manifest-validate layer rather than waiting for the apiserver
4546    /// — the same fail-at-the-source posture every peer per-axis
4547    /// value-shape gate (DNS-1123 on `:nome`, SemVer-2 on `:versao`,
4548    /// SPDX-expression-shape on `:licenca`, 4-digit decimal year on
4549    /// `:edicao`, etc.) takes.
4550    ///
4551    /// Thin wrapper around
4552    /// [`crate::render::is_lareira_chart_name_shape`] (the
4553    /// substrate-side predicate that composes [`lareira_chart_name`] +
4554    /// [`is_dns_1123_label`] via the lifted
4555    /// [`crate::LAREIRA_CHART_NAME_NOME_MAX_LEN`] budget); maps the
4556    /// shared parser-shaped reason into the
4557    /// [`ManifestError::NomeChartNameBudgetExceeded`] variant so the
4558    /// diagnostic is self-locating (the offending `:nome` is named
4559    /// verbatim alongside the rendered chart name and the budget) and
4560    /// the author can shorten in one edit. The gate runs across every
4561    /// `:kind` — `:nome` is the substrate-wide identity axis any
4562    /// future renderer the substrate adds can derive a
4563    /// `lareira-<nome>` artifact from, and uniform enforcement closes
4564    /// the drift footgun where a future kind grows a chart-emitting
4565    /// render path while the validate cascade doesn't catch it.
4566    ///
4567    /// Runs *after* [`Self::validate_nome`] so the narrower
4568    /// `NomeEmpty` / `NomeInvalid` shape diagnostics fire first — a
4569    /// structurally-malformed `:nome` (empty, uppercase, underscore,
4570    /// dot, leading/trailing hyphen, Unicode, > 63 bytes) surfaces its
4571    /// specific shape error rather than the chart-name-budget error,
4572    /// preserving the legitimate "well-shaped `:nome` that happens to
4573    /// overflow the joint cap" arm for this gate.
4574    pub fn validate_nome_chart_name_budget(&self) -> Result<(), ManifestError> {
4575        let nome = self.nome();
4576        crate::render::is_lareira_chart_name_shape(nome)
4577            .map_err(|reason| ManifestError::nome_chart_name_budget_exceeded(nome, reason))
4578    }
4579
4580    /// Reject `:versao` values that don't parse as [`semver::Version`].
4581    /// The top-level Caixa version flows directly into every
4582    /// substrate-side artifact that carries a "this is which version of
4583    /// the caixa" axis: the `lareira-<nome>` Helm chart's `Chart.yaml`
4584    /// `version:` + `appVersion:` axes ([`caixa-helm::lib`] —
4585    /// SemVer-2-strict at `helm template` / `helm install` time per
4586    /// https://helm.sh/docs/topics/charts/#charts-and-versioning), the
4587    /// `feira publish` Zig-style `v<versao>` git tag
4588    /// ([`caixa-flux::lib::programs_yaml_entry`] / the
4589    /// `caixa-publish.yml` reusable workflow), the programs.yaml entry's
4590    /// `versao:` value the `lareira-fleet-programs` aggregator carries
4591    /// onto each rendered ComputeUnit, the OCI image's `:v<versao>` /
4592    /// `:latest` tags the substrate's `wasi-service-flake` builds with
4593    /// `skopeo push`, the lacre closure's pinned versions
4594    /// ([`caixa-resolver`] keys `concrete_versao`), and the
4595    /// `:upgrade-from :from` references peers in this exact `versao`
4596    /// shape (`semver::Version`, not `VersionReq`). Each consumer
4597    /// expects a strict three-part `MAJOR.MINOR.PATCH` (optionally
4598    /// `-prerelease` and/or `+build`); a structurally invalid `:versao`
4599    /// (`"0.1"` — missing patch, the canonical "I shortened it" footgun;
4600    /// `"v0.1.0"` — the git-tag-shape-leaking-into-versao typo;
4601    /// `"latest"` / `"main"` — the "I confused it with a docker tag"
4602    /// footgun; `"^0.1"` / `"~0.1.2"` — the requirement-shape leaking
4603    /// into the version field a peer `:deps :versao` accepts;
4604    /// `"0.1.0.0"` — the four-part Java/Microsoft convention DNS
4605    /// SemVer-2 forbids) silently passed [`Caixa::from_lisp`] (the
4606    /// derive macro stores the raw String) and the failure surfaced at
4607    /// the *first* downstream consumer that strict-parses it: at
4608    /// `helm install` time as a chart-version rejection, at
4609    /// `feira publish` time as a malformed git tag, at lacre-resolve
4610    /// time as a `semver::Error` not naming the offending caixa, at
4611    /// `feira upgrade --to <versao>` time as an unresolvable
4612    /// `:upgrade-from :from` match — far from the source `caixa.lisp`
4613    /// and without any field naming the offending `:versao`.
4614    ///
4615    /// Thin wrapper around [`semver::Version::parse`] — the same parser
4616    /// [`crate::CaixaVersion::parse`] (the typed `:versao` accessor)
4617    /// and [`crate::UpgradeFromEntry::validate`] (the peer
4618    /// `:upgrade-from :from` axis, 26da2c7) consume. Maps the
4619    /// `semver::Error` reason into the [`ManifestError::VersaoInvalid`]
4620    /// variant, carrying the offending `:versao` verbatim + a
4621    /// parser-shaped reason naming the specific violation, so the
4622    /// diagnostic is self-locating (the author can grep their
4623    /// `caixa.lisp` for `:versao "<value>"` and fix it in one edit).
4624    /// Same diagnostic shape as [`ManifestError::NomeInvalid`]
4625    /// (6c992f8) and [`crate::UpgradeError::FromInvalid`]
4626    /// (b0c8389) on the peer axes. With this gate, the typed `:versao`
4627    /// surfaces — top-level `:versao`, `:upgrade-from :from` — are
4628    /// now structurally equivalent (every value past validate is
4629    /// round-trippable through [`semver::Version::parse`] without
4630    /// re-checking at the renderer, resolver, or operator hot-upgrade
4631    /// layer), peer with the four `:versao` requirement axes (`:deps`,
4632    /// `:deps-dev`, `:membros`, `:children`) the prior commits
4633    /// (2420c44, 9888b13, b38ff3a) wired through `parse_requirement`.
4634    ///
4635    /// Empty `:versao` (which [`Caixa::from_lisp`] does not reject —
4636    /// the derive macro stores the raw String) is gated by the
4637    /// narrower [`ManifestError::VersaoEmpty`] arm before the parser is
4638    /// consulted, mirroring the empty-first cascade every per-axis
4639    /// version gate already uses (e.g. `MembroVersaoEmpty` before
4640    /// `MembroVersaoInvalid`, `EmptyChildVersion` before
4641    /// `ChildVersaoInvalid`, `NomeEmpty` before `NomeInvalid`).
4642    pub fn validate_versao(&self) -> Result<(), ManifestError> {
4643        let versao = self.versao();
4644        if versao.is_empty() {
4645            return Err(ManifestError::VersaoEmpty);
4646        }
4647        semver::Version::parse(versao)
4648            .map_err(|e| ManifestError::versao_invalid(versao, e.to_string()))?;
4649        Ok(())
4650    }
4651
4652    /// Compound per-`Caixa` entry gate on the M2 `:upgrade-from` slot:
4653    /// folds the three [`crate::upgrade`] top-level validators — the
4654    /// per-entry shape + cross-entry duplicate-`:from` gate
4655    /// ([`crate::upgrade::validate_upgrade_from`]), the cross-slot
4656    /// `:from < :versao` SemVer-2 precedence gate
4657    /// ([`crate::upgrade::validate_upgrade_from_against_versao`]), and the
4658    /// cross-slot `:state-change` ↔ `:on-state-change` composition gate
4659    /// ([`crate::upgrade::validate_upgrade_from_against_behavior`]) — onto
4660    /// one substrate primitive on [`Caixa`]. The three dispatches run in
4661    /// the same order the layout pipeline
4662    /// ([`crate::layout::StandardLayout::verify`], the `feira build`
4663    /// author-time gate) has always sequenced them, so the fold is
4664    /// byte-for-byte equivalent to the pre-fold three-block cascade at
4665    /// that call site (pinned by the per-arm
4666    /// `validate_upgrade_from_folds_per_entry_arm_matches_gate` /
4667    /// `_folds_versao_arm_matches_gate` / `_folds_behavior_arm_matches_gate`
4668    /// equivalence pins and by the cross-arm
4669    /// `validate_upgrade_from_per_entry_arm_fires_before_versao_arm` /
4670    /// `_versao_arm_fires_before_behavior_arm` ordering pins).
4671    ///
4672    /// Prior to this lift the three [`crate::upgrade`] top-level validators
4673    /// lived only open-coded at the layout wire-up site
4674    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4675    /// each threaded through the same `self.upgrade_from()` slice and each
4676    /// paired with the same [`crate::LayoutError::UpgradeViolation`]-wrap
4677    /// envelope: every future consumer that wanted to gate `:upgrade-from`
4678    /// as a whole — the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
4679    /// materializer's per-CR admission webhook re-checking `:upgrade-from`
4680    /// after a per-`(:from … :instructions …)` patch, a future `feira
4681    /// validate --upgrade` per-caixa admission verb, a per-`:upgrade-from`
4682    /// overlay resolver a per-cluster overlay lift would materialize —
4683    /// was structurally forced to either re-inline the three-dispatch
4684    /// cascade in lockstep with the layout wire-up (the duplication the
4685    /// PRIME DIRECTIVE names as a bug) or call the whole
4686    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4687    /// peer per-Caixa gate to re-check one slot. Post-fold each such
4688    /// consumer reaches the three-arm compound gate through one call on
4689    /// the substrate primitive.
4690    ///
4691    /// The three arms together name one contract with three axes:
4692    ///
4693    ///   - **per-entry + cross-entry graph-edge invariant** — every entry's
4694    ///     `:from` parses as SemVer-2 and every per-instruction / within-
4695    ///     entry ordering / singularity gate on each entry's
4696    ///     `:instructions` list passes, and no two entries share the same
4697    ///     parsed `:from` (the wasm-operator's OTP appup
4698    ///     `release_handler:install_release/1` analog picks at most one
4699    ///     matching block per running version — two entries with the same
4700    ///     parsed semver are an ambiguous edge in the typed upgrade graph).
4701    ///   - **cross-slot reachability invariant** — every entry's `:from`
4702    ///     is strictly less than the caixa's own `:versao` under SemVer-2
4703    ///     precedence. An entry whose `:from >= :versao` is structurally
4704    ///     unreachable by the operator's `:from`-match dispatch (the
4705    ///     operator loads the current `:versao` and matches the *running*
4706    ///     version against each entry's `:from`; an entry whose `:from >=
4707    ///     :versao` is never reached because the operator never runs a
4708    ///     version >= the current one that it could then upgrade *to* the
4709    ///     current one).
4710    ///   - **cross-slot composition invariant** — every entry carrying a
4711    ///     `(:state-change …)` instruction has a `:behavior
4712    ///     :on-state-change` callback declared on the same caixa. The
4713    ///     per-version migration script is the `gen_server:code_change/3`
4714    ///     analog and the runtime hook it is delivered through during hot
4715    ///     upgrade is the `:on-state-change` callback (the upgrade.rs
4716    ///     module doc pins the composition verbatim: "Composes with the
4717    ///     `:behavior :on-state-change` callback to deliver state migration
4718    ///     during hot upgrades").
4719    ///
4720    /// All three axes must hold together — every consumer's
4721    /// `:upgrade-from` accept-set past this compound gate is the same
4722    /// set the `feira build` author-time gate admits.
4723    ///
4724    /// The per-slot compound entry gate discipline lifted here onto the
4725    /// M2 `:upgrade-from` axis is the sibling of the peer per-kind
4726    /// compound entry gates ([`crate::render::require_supervisor_view`]
4727    /// / [`crate::render::require_aplicacao_view`] /
4728    /// [`crate::render::require_v0_servico_shape`]) that fold every
4729    /// per-kind cascade at the per-kind altitude, and of the peer
4730    /// per-slot compound gates ([`crate::AplicacaoSpec::validate_contratos`],
4731    /// [`crate::MeshPolicy::validate`],
4732    /// [`crate::SupervisorSpec::validate_children`]) that fold every
4733    /// structural axis on their slot onto one substrate primitive.
4734    /// Extended here to the last unlifted compound-cascade wire-up at
4735    /// the layout-pipeline altitude — the three-dispatch M2
4736    /// `:upgrade-from` cascade that lived only open-coded at the layout
4737    /// wire-up site.
4738    ///
4739    /// The per-instruction script-path on-disk existence-probe walk that
4740    /// [`crate::layout::StandardLayout::verify`] runs immediately after
4741    /// this gate (which resolves each entry's `:instructions
4742    /// (:state-change :script)` against the layout root) stays open-coded
4743    /// at the layout wire-up site — that arm needs the filesystem oracle
4744    /// on the [`crate::LayoutInvariants`] trait, not the pure per-Caixa
4745    /// typed-shape surface this compound gate folds. Same posture the
4746    /// peer [`Self::validate_code_paths`] takes on the sibling code-path
4747    /// axes: the typed-shape gate fires on the per-Caixa surface, the
4748    /// on-disk existence check fires on the [`crate::StandardLayout`]
4749    /// surface.
4750    ///
4751    /// # Errors
4752    ///
4753    /// Returns [`crate::UpgradeError::FromInvalid`] /
4754    /// [`crate::UpgradeError::ModuleEmpty`] /
4755    /// [`crate::UpgradeError::ModuleInvalid`] /
4756    /// [`crate::UpgradeError::EmptyScript`] /
4757    /// [`crate::UpgradeError::AbsoluteScript`] /
4758    /// [`crate::UpgradeError::ParentEscapeScript`] /
4759    /// [`crate::UpgradeError::NonLispExtensionScript`] /
4760    /// [`crate::UpgradeError::RestartNotExclusive`] /
4761    /// [`crate::UpgradeError::StateChangeWithoutPriorLoad`] /
4762    /// [`crate::UpgradeError::PurgeWithoutPriorLoad`] /
4763    /// [`crate::UpgradeError::StateChangeAfterCleanup`] /
4764    /// [`crate::UpgradeError::DuplicateLoadModule`] /
4765    /// [`crate::UpgradeError::DuplicateStateChange`] /
4766    /// [`crate::UpgradeError::DuplicateCleanup`] /
4767    /// [`crate::UpgradeError::DuplicateFrom`] on the per-entry +
4768    /// cross-entry axis; [`crate::UpgradeError::FromNotBeforeVersao`] on
4769    /// the cross-slot `:from ↔ :versao` axis;
4770    /// [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
4771    /// on the cross-slot `:state-change ↔ :on-state-change` axis.
4772    pub fn validate_upgrade_from(&self) -> Result<(), crate::UpgradeError> {
4773        crate::upgrade::validate_upgrade_from(self.upgrade_from())?;
4774        crate::upgrade::validate_upgrade_from_against_versao(self.upgrade_from(), self.versao())?;
4775        crate::upgrade::validate_upgrade_from_against_behavior(
4776            self.upgrade_from(),
4777            self.behavior(),
4778        )?;
4779        Ok(())
4780    }
4781
4782    /// Compound per-`Caixa` entry gate on the M2 `:limits` slot — folds
4783    /// the [`crate::LimitsSpec::validate`] four-axis cascade (`:memory`
4784    /// wasm32 zero-floor / below-page / above-cap / non-page-multiple;
4785    /// `:fuel` zero-floor / cap; `:wall-clock` zero-floor / cap; `:cpu`
4786    /// zero-floor / cap) onto one substrate primitive on [`Caixa`]. The
4787    /// `#[serde(default)]` absent-slot arm (`limits: None`, the
4788    /// canonical "no bound declared — engine-default applies" author
4789    /// shape [`crate::LimitsSpec::is_empty`]'s per-axis `None` cascade
4790    /// reads) is the fold's identity element and passes trivially; the
4791    /// present-slot arm (`limits: Some(l)`) dispatches to
4792    /// [`crate::LimitsSpec::validate`] verbatim, threading its per-axis
4793    /// [`crate::LimitsError`] Display through untouched.
4794    ///
4795    /// Prior to this lift the M2 `:limits` slot lived only wired
4796    /// open-coded at the layout wire-up site
4797    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
4798    /// through the `if let Some(l) = caixa.limits() { l.validate() … }`
4799    /// three-line `Option::None → Ok(()) | Some(_) → …` unwrap-and-
4800    /// dispatch pattern paired with the same
4801    /// [`crate::LayoutError::LimitsViolation`]-wrap envelope: every
4802    /// future consumer that wanted to gate `:limits` as a whole — the
4803    /// deferred `caixa.pleme.io/v1alpha1/Caixa` CR materializer's
4804    /// per-CR admission webhook re-checking `:limits` after a per-
4805    /// `{:memory, :fuel, :wall-clock, :cpu}` patch (the exact case the
4806    /// [`Self::limits`] accessor docstring names as the second
4807    /// consumer of the slot), a future `feira validate --limits` per-
4808    /// caixa admission verb, a per-`:limits` overlay resolver a per-
4809    /// cluster `:limits-overrides` overlay lift would materialize — was
4810    /// structurally forced to either re-inline the two-line
4811    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4812    /// pattern in lockstep with the layout wire-up (the duplication the
4813    /// PRIME DIRECTIVE names as a bug) or call the whole
4814    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4815    /// peer per-Caixa gate ([`Self::validate_nome`],
4816    /// [`Self::validate_versao`], [`Self::validate_deps`],
4817    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4818    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4819    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4820    /// [`Self::validate_upgrade_from`], [`Self::validate_code_paths`],
4821    /// plus the per-kind `require_supervisor_view` /
4822    /// `require_aplicacao_view` gates, plus the on-disk existence
4823    /// walks) to re-check one slot. Post-lift each such consumer
4824    /// reaches the [`crate::LimitsSpec::validate`] four-axis cascade
4825    /// (and its identity-element on the absent slot) through one call
4826    /// on the substrate primitive.
4827    ///
4828    /// The per-slot compound entry-gate discipline lifted here onto the
4829    /// M2 `:limits` axis is the sibling of the peer per-slot compound
4830    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4831    /// [`crate::MeshPolicy::validate`],
4832    /// [`crate::SupervisorSpec::validate_children`],
4833    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`]) that
4834    /// fold every structural + cross-slot axis on their slot onto one
4835    /// substrate primitive. Extended here to the M2 `:limits` slot, the
4836    /// first of the two M2 typed slots (`:limits`, `:behavior`) whose
4837    /// per-Caixa compound-gate wire-up still lived open-coded at the
4838    /// layout altitude after the [`Self::validate_upgrade_from`] lift
4839    /// (d6801df) closed the sibling M2 slot's cascade.
4840    ///
4841    /// # Errors
4842    ///
4843    /// Returns every [`crate::LimitsError`] variant on the present-slot
4844    /// arm — verbatim from [`crate::LimitsSpec::validate`]. Passes
4845    /// trivially on the absent-slot arm (`limits: None`, the fold's
4846    /// identity element).
4847    pub fn validate_limits(&self) -> Result<(), crate::LimitsError> {
4848        match self.limits() {
4849            Some(l) => l.validate(),
4850            None => Ok(()),
4851        }
4852    }
4853
4854    /// Compound per-`Caixa` entry gate on the M2 `:behavior` slot's
4855    /// pure typed-shape surface — folds the
4856    /// [`crate::BehaviorSpec::validate`] six-slot value-shape cascade
4857    /// (each declared `:on-init` / `:on-call` / `:on-cast` / `:on-info`
4858    /// / `:on-state-change` / `:on-terminate` callback-path is
4859    /// non-empty / relative / no-`..`-parent-escape / terminating-
4860    /// `.lisp`-extension, routed through the shared
4861    /// [`crate::render::require_sandboxed_lisp_path`] arm-set) onto one
4862    /// substrate primitive on [`Caixa`]. The `#[serde(default)]`
4863    /// absent-slot arm (`behavior: None`, the canonical "no callback
4864    /// declared — the runtime falls back to the wasm-engine's default
4865    /// callback per arm" author shape [`crate::BehaviorSpec::is_empty`]'s
4866    /// per-slot `None` cascade reads) is the fold's identity element
4867    /// and passes trivially; the present-slot arm (`behavior: Some(b)`)
4868    /// dispatches to [`crate::BehaviorSpec::validate`] verbatim,
4869    /// threading its per-slot [`crate::BehaviorError`] Display through
4870    /// untouched.
4871    ///
4872    /// Scope note — the on-disk callback-path existence walk paired
4873    /// with the value-shape gate at
4874    /// [`crate::layout::StandardLayout::verify`] stays open-coded at
4875    /// the layout altitude, because it needs the
4876    /// [`crate::layout::LayoutInvariants`] filesystem oracle
4877    /// ([`crate::layout::LayoutInvariants::exists`]) that the pure
4878    /// per-Caixa typed-shape surface this compound gate folds onto has
4879    /// no reference to. Same posture the peer M2 `:upgrade-from`
4880    /// per-Caixa compound gate ([`Self::validate_upgrade_from`]
4881    /// d6801df) already carries: the pure typed-shape surface folds
4882    /// onto the substrate primitive; the per-instruction script-path
4883    /// existence probe on the paired axis (there `:state-change
4884    /// :script`; here `:on-*`) stays at the layout altitude.
4885    ///
4886    /// Prior to this lift the pure value-shape surface of the M2
4887    /// `:behavior` slot lived only wired open-coded at the layout
4888    /// wire-up site ([`crate::layout::StandardLayout::verify`],
4889    /// caixa-core/src/layout.rs), through the
4890    /// `if let Some(b) = caixa.behavior() { b.validate() … }`
4891    /// unwrap-and-dispatch pattern paired with the same
4892    /// [`crate::LayoutError::BehaviorViolation`]-wrap envelope: every
4893    /// future consumer that wanted to gate the `:behavior` slot's
4894    /// value-shape as a whole — the deferred
4895    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
4896    /// admission webhook re-checking `:behavior` after a per-`{:on-init,
4897    /// :on-call, :on-cast, :on-info, :on-state-change, :on-terminate}`
4898    /// patch (the exact case the peer `:on-*` accessor docstrings on
4899    /// [`crate::BehaviorSpec`] already name as deferred consumers of
4900    /// the slot), a future `feira validate --behavior` per-caixa
4901    /// admission verb, a per-`:behavior` overlay resolver a future
4902    /// per-cluster callback-overlay lift would materialize — was
4903    /// structurally forced to either re-inline the two-line
4904    /// `Option::None → Ok(()) | Some(_) → …` unwrap-and-dispatch
4905    /// pattern in lockstep with the layout wire-up (the duplication the
4906    /// PRIME DIRECTIVE names as a bug) or call the whole
4907    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
4908    /// peer per-Caixa gate ([`Self::validate_nome`],
4909    /// [`Self::validate_versao`], [`Self::validate_deps`],
4910    /// [`Self::validate_etiquetas`], [`Self::validate_autores`],
4911    /// [`Self::validate_repositorio`], [`Self::validate_descricao`],
4912    /// [`Self::validate_licenca`], [`Self::validate_edicao`],
4913    /// [`Self::validate_limits`], [`Self::validate_upgrade_from`],
4914    /// [`Self::validate_code_paths`], plus the per-kind
4915    /// `require_supervisor_view` / `require_aplicacao_view` gates, plus
4916    /// the on-disk existence walks) to re-check one slot. Post-lift
4917    /// each such consumer reaches the [`crate::BehaviorSpec::validate`]
4918    /// six-slot cascade (and its identity-element on the absent slot)
4919    /// through one call on the substrate primitive.
4920    ///
4921    /// The per-slot compound entry-gate discipline lifted here onto the
4922    /// M2 `:behavior` axis is the sibling of the peer per-slot compound
4923    /// gates ([`crate::AplicacaoSpec::validate_contratos`],
4924    /// [`crate::MeshPolicy::validate`],
4925    /// [`crate::SupervisorSpec::validate_children`],
4926    /// [`Self::validate_upgrade_from`], [`Self::validate_deps`],
4927    /// [`Self::validate_limits`]) that fold every structural + cross-
4928    /// slot axis on their slot onto one substrate primitive. Extended
4929    /// here to the M2 `:behavior` slot, the last of the four M2 typed
4930    /// slots (`:limits`, `:behavior`, `:upgrade-from`, plus the
4931    /// supervisor-only `:children` peer) whose per-Caixa compound-gate
4932    /// wire-up still lived open-coded at the layout altitude after the
4933    /// [`Self::validate_limits`] lift (baa4688) closed the sibling M2
4934    /// `:limits` slot's cascade. With this lift the "one named per-slot
4935    /// / per-Caixa compound gate per typed slot folding every structural
4936    /// axis on that slot (plus the `Option::None` identity element for
4937    /// the `Option`-shaped slots) onto one substrate primitive"
4938    /// discipline spans every M2 typed slot uniformly, so a reader who
4939    /// has learned any peer M2 gate reads `:behavior` without a per-
4940    /// slot exception carve-out.
4941    ///
4942    /// # Errors
4943    ///
4944    /// Returns every [`crate::BehaviorError`] variant on the present-
4945    /// slot arm — verbatim from [`crate::BehaviorSpec::validate`].
4946    /// Passes trivially on the absent-slot arm (`behavior: None`, the
4947    /// fold's identity element).
4948    pub fn validate_behavior(&self) -> Result<(), crate::BehaviorError> {
4949        match self.behavior() {
4950            Some(b) => b.validate(),
4951            None => Ok(()),
4952        }
4953    }
4954
4955    /// Reject `:restart-window` values the shared
4956    /// [`crate::supervisor::duration_codec::parse`] refuses. The flat
4957    /// `restart_window: Option<String>` slot on [`Caixa`] is stored
4958    /// raw by the derive macro (the typed [`SupervisorSpec`] holds an
4959    /// `Option<Duration>` routed through the shared codec via `with =
4960    /// "duration_codec"`); the inline `Caixa → SupervisorSpec`
4961    /// view-construction path ([`Self::supervisor_view`]) folds the
4962    /// raw string through the same shared codec and soft-swallows the
4963    /// parse error as `None` to keep the view best-effort. Without
4964    /// this gate a malformed `:restart-window` (`"1.5s"` — the
4965    /// fractional-seconds drift class; `"1.0s"` — the decimal-shaped
4966    /// integer drift; `"0.5m"` — the unit-fraction drift; `"+30s"` /
4967    /// `"-30s"` — the leading-sign drift; `"30x"` — the unknown-unit
4968    /// footgun; `"abc"` — pure garbage; `""` — the empty-after-trim
4969    /// edge case) silently produced a `SupervisorSpec` with
4970    /// `restart_window: None`, indistinguishable from the canonical
4971    /// "omit the slot to express no reset" authoring shape — Erlang/OTP's
4972    /// `MaxIntensity / Period` invariant turns into a never-reset
4973    /// supervisor far from the source `caixa.lisp`, with no field
4974    /// naming the offending `:restart-window`. Lifting the gate to a
4975    /// Caixa-level validator mirrors the trajectory of the peer
4976    /// per-axis identity gates ([`Self::validate_nome`] 6c992f8,
4977    /// [`Self::validate_versao`] 1fdaa02, [`Self::validate_deps`]
4978    /// a7f0d8c) and the ABSORPTION-ROADMAP.md M2.2 test pin
4979    /// (line 196: "reject invalid `:restart-window` (non-duration)").
4980    ///
4981    /// Thin wrapper around [`crate::supervisor::duration_codec::parse`]
4982    /// (the shared codec backing `:supervisor :restart-window` as
4983    /// serde-routed on [`SupervisorSpec`], `:politicas :timeout`, and
4984    /// `:politicas :circuit-breaker :window` — all three covered by
4985    /// the integer-magnitude gate 1c55a2a). Maps the codec's parse
4986    /// error verbatim into the [`ManifestError::RestartWindowMalformed`]
4987    /// variant, carrying the offending raw string + a parser-shaped
4988    /// reason naming the canonical authoring form, so the diagnostic
4989    /// is self-locating (the author can grep their `caixa.lisp` for
4990    /// `:restart-window "<value>"` and fix it in one edit) and
4991    /// uniform with every other manifest-level validate diagnostic.
4992    /// With this gate the four `:restart-window`-shaped surfaces (the
4993    /// flat raw string on [`Caixa`], the typed `Option<Duration>` on
4994    /// [`SupervisorSpec`], the two `MeshPolicy` peer durations) are
4995    /// now structurally equivalent — every value past the codec is in
4996    /// one accepted set, by construction.
4997    ///
4998    /// `None` (the canonical "omit the slot to express no reset"
4999    /// shape) is accepted trivially — the gate is a no-op when the
5000    /// author didn't author a window. The empty string is rejected by
5001    /// the shared codec (its digit-only gate refuses an empty
5002    /// magnitude), surfacing the same `RestartWindowMalformed`
5003    /// diagnostic as every other rejected non-canonical shape.
5004    pub fn validate_restart_window(&self) -> Result<(), ManifestError> {
5005        let Some(s) = self.restart_window() else {
5006            return Ok(());
5007        };
5008        crate::supervisor::duration_codec::parse(s)
5009            .map(|_| ())
5010            .map_err(|reason| ManifestError::restart_window_malformed(s, reason))
5011    }
5012
5013    /// Compound per-`Caixa` entry gate on the Aplicacao-kind mesh-slot
5014    /// family — folds the paired [`crate::AplicacaoSpec::validate`]
5015    /// typed-shape cascade (per-slot gates on `:membros`, `:contratos`,
5016    /// `:entrada`, `:placement`, `:politicas`, in that declared order)
5017    /// plus the cross-slot self-edge gate
5018    /// ([`crate::aplicacao::validate_no_self_membership`], the
5019    /// `:membros :caixa` ≠ `:nome` invariant the typed view cannot
5020    /// enforce on its own because it carries the membros but not the
5021    /// parent `:nome`) onto one substrate primitive on [`Caixa`]. On
5022    /// non-Aplicacao kinds the fold is the identity element — the paired
5023    /// [`Self::aplicacao_view`] accessor returns `None` off the
5024    /// Aplicacao arm (peer with the [`Self::validate_limits`] /
5025    /// [`Self::validate_behavior`] M2 `Option`-arm identity element),
5026    /// so the gate passes trivially without touching the mesh slots.
5027    ///
5028    /// Prior to this lift the paired cascade lived only wired open-coded
5029    /// at the layout wire-up site
5030    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
5031    /// as the three-line `let view = caixa.aplicacao_view().expect(...);
5032    /// view.validate() … validate_no_self_membership(...) …` pattern
5033    /// paired with two `.map_err(|err| LayoutError::AplicacaoViolation
5034    /// { caixa, issue })` wraps — every future consumer that wanted to
5035    /// gate the Aplicacao-shape cascade as a whole (the deferred
5036    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-CR
5037    /// admission webhook re-checking `:membros` / `:contratos` after a
5038    /// per-slot patch, a future `feira validate --aplicacao` per-caixa
5039    /// admission verb, a per-Aplicacao overlay resolver) was structurally
5040    /// forced to either re-inline the two-dispatch cascade in lockstep
5041    /// with the layout wire-up (the duplication the PRIME DIRECTIVE
5042    /// names as a bug) or call the whole
5043    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
5044    /// peer per-Caixa gate to re-check one slot family. Post-fold each
5045    /// such consumer reaches the two-arm compound gate through one call
5046    /// on the substrate primitive.
5047    ///
5048    /// Peer to the [`crate::render::require_aplicacao_view`] compound
5049    /// entry gate every per-Aplicacao *renderer* routes through
5050    /// (3aefefb folded `validate_no_self_membership` onto the renderer
5051    /// path) — this gate mirrors the same fold on the *layout* path, so
5052    /// the two consumers of the Aplicacao-shape cascade (the author-time
5053    /// gate and every per-Aplicacao renderer) share one substrate
5054    /// primitive rather than two open-coded cascades kept in lockstep.
5055    /// Same lift discipline the peer per-slot compound gates
5056    /// ([`Self::validate_upgrade_from`] d6801df, [`Self::validate_deps`]
5057    /// b5dd55e, [`Self::validate_limits`] baa4688,
5058    /// [`Self::validate_behavior`] 0d2877a) each carry.
5059    ///
5060    /// # Errors
5061    ///
5062    /// Returns every [`crate::AplicacaoError`] variant on the present-
5063    /// kind arm — the typed-shape cascade's per-slot arms first
5064    /// (matching [`crate::AplicacaoSpec::validate`]'s declared order),
5065    /// then the cross-slot self-edge arm
5066    /// ([`crate::AplicacaoError::MembroIsSelfAplicacao`]). Passes
5067    /// trivially on non-Aplicacao kinds (the fold's identity element).
5068    pub fn validate_aplicacao_shape(&self) -> Result<(), crate::AplicacaoError> {
5069        let Some(view) = self.aplicacao_view() else {
5070            return Ok(());
5071        };
5072        view.validate()?;
5073        crate::aplicacao::validate_no_self_membership(self.membros(), self.nome())?;
5074        Ok(())
5075    }
5076
5077    /// Compound per-`Caixa` entry gate on the Supervisor-kind
5078    /// supervision-tree slot family — folds the paired
5079    /// [`crate::SupervisorSpec::validate`] typed-shape cascade
5080    /// (`:estrategia` ↔ `:children` invariants, `:max-restarts` /
5081    /// `:restart-window` bounds, per-child DNS-1123 `:caixa` names,
5082    /// semver-valid `:versao` constraints, the set-not-multiset
5083    /// duplicate-child gate) plus the cross-slot self-edge gate
5084    /// ([`crate::supervisor::validate_no_self_supervision`], the
5085    /// `:children :caixa` ≠ `:nome` invariant the typed view cannot
5086    /// enforce on its own because it carries the children but not the
5087    /// parent `:nome`) onto one substrate primitive on [`Caixa`]. On
5088    /// non-Supervisor kinds the fold is the identity element — the paired
5089    /// [`Self::supervisor_view`] accessor returns `None` off the
5090    /// Supervisor arm (peer with the [`Self::validate_limits`] /
5091    /// [`Self::validate_behavior`] M2 `Option`-arm identity element and
5092    /// the sibling per-Aplicacao [`Self::validate_aplicacao_shape`]),
5093    /// so the gate passes trivially without touching the supervision-tree
5094    /// slots.
5095    ///
5096    /// Prior to this lift the paired cascade lived only wired open-coded
5097    /// at the layout wire-up site
5098    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/layout.rs),
5099    /// as the three-line `let view = caixa.supervisor_view().expect(...);
5100    /// view.validate() … validate_no_self_supervision(...) …` pattern
5101    /// paired with two `.map_err(|err| LayoutError::SupervisorViolation
5102    /// { caixa, issue })` wraps — every future consumer that wanted to
5103    /// gate the Supervisor-shape cascade as a whole (the wasm-operator's
5104    /// hierarchical reconciliation scheduler re-checking `:children` /
5105    /// `:estrategia` after a per-slot patch, the M4
5106    /// `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's admission
5107    /// webhook, a future `feira validate --supervisor` per-caixa
5108    /// admission verb, a per-Supervisor overlay resolver) was structurally
5109    /// forced to either re-inline the two-dispatch cascade in lockstep
5110    /// with the layout wire-up (the duplication the PRIME DIRECTIVE
5111    /// names as a bug) or call the whole
5112    /// [`crate::layout::StandardLayout::verify`] pipeline and pay every
5113    /// peer per-Caixa gate to re-check one slot family. Post-fold each
5114    /// such consumer reaches the two-arm compound gate through one call
5115    /// on the substrate primitive.
5116    ///
5117    /// Peer to the [`crate::render::require_supervisor_view`] compound
5118    /// entry gate every per-Supervisor *renderer* would route through
5119    /// (which already folds the same `spec.validate()` +
5120    /// `validate_no_self_supervision` two-arm cascade behind its
5121    /// `require_kind` + `validate_restart_window` prelude) — this gate
5122    /// mirrors the same fold on the *layout* path, so the two consumers
5123    /// of the Supervisor-shape cascade (the author-time gate and every
5124    /// per-Supervisor renderer) share one substrate primitive rather
5125    /// than two open-coded cascades kept in lockstep. Same lift
5126    /// discipline the peer per-slot compound gates
5127    /// ([`Self::validate_aplicacao_shape`] 949a7a0,
5128    /// [`Self::validate_upgrade_from`] d6801df,
5129    /// [`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5130    /// baa4688, [`Self::validate_behavior`] 0d2877a) each carry.
5131    ///
5132    /// # Errors
5133    ///
5134    /// Returns every [`crate::SupervisorError`] variant on the present-
5135    /// kind arm — the typed-shape cascade's per-slot arms first
5136    /// (matching [`crate::SupervisorSpec::validate`]'s declared order),
5137    /// then the cross-slot self-edge arm
5138    /// ([`crate::SupervisorError::ChildSupervisesSelf`]). Passes
5139    /// trivially on non-Supervisor kinds (the fold's identity element).
5140    pub fn validate_supervisor_shape(&self) -> Result<(), crate::SupervisorError> {
5141        let Some(view) = self.supervisor_view() else {
5142            return Ok(());
5143        };
5144        view.validate()?;
5145        crate::supervisor::validate_no_self_supervision(self.children(), self.nome())?;
5146        Ok(())
5147    }
5148
5149    /// Compound per-`Caixa` entry gate on the Acao-kind `:ci` slot
5150    /// family — folds the [`crate::decompose_ci`] typed decompose gate
5151    /// (`canteiro_types::decompose` refusing every illegal
5152    /// [`canteiro_types::CiRun`] shape: duplicate node name, dependency
5153    /// on an undeclared node, dependency cycle) onto one substrate
5154    /// primitive on [`Caixa`]. On non-`Acao` kinds the fold is the
5155    /// identity element — the paired [`Self::kind`] `is_acao()` guard
5156    /// short-circuits before the decompose gate ever fires (peer with
5157    /// the [`Self::validate_aplicacao_shape`] /
5158    /// [`Self::validate_supervisor_shape`] typed-view identity element
5159    /// and the [`Self::validate_limits`] / [`Self::validate_behavior`]
5160    /// M2 `Option`-arm identity element), so the gate passes trivially
5161    /// without touching the `:ci` slot. An `:kind Acao` caixa with
5162    /// `ci = None` is also an identity-element pass: the presence gate
5163    /// is the sibling axis owned by [`crate::LayoutError::MissingCi`] /
5164    /// [`crate::require_ci`] / [`crate::MissingCiSlot`], not by the
5165    /// decompose gate — a caixa that carries no `:ci` slot has no run
5166    /// to decompose. Same split the peer per-Servico
5167    /// [`crate::LayoutError::ServicoWithoutServicos`] presence gate and
5168    /// per-Binario [`crate::LayoutError::BinarioWithoutExe`] presence
5169    /// gate keep from their sibling per-slot shape gates, so the two
5170    /// axes stay separately diagnosable at the layout altitude.
5171    ///
5172    /// Prior to this lift the decompose gate lived only wired
5173    /// open-coded at the [`caixa_actions::validate`] renderer-side
5174    /// entry gate (routed through the substrate-canonical
5175    /// [`crate::require_acao_view`] compound helper) — the *layout*
5176    /// pipeline ([`crate::layout::StandardLayout::verify`], caixa-core/
5177    /// src/layout.rs) only checked `:ci` *presence* via
5178    /// [`crate::LayoutError::MissingCi`], so a `:kind Acao` caixa
5179    /// carrying a structurally illegal `:ci` (a duplicate node name, a
5180    /// dependency on an undeclared node, a dependency cycle) passed
5181    /// `feira build` cleanly and surfaced the diagnostic only when
5182    /// [`caixa_actions::validate`] later refused it — far from the
5183    /// source `caixa.lisp` on the author-time gate side. Every future
5184    /// consumer that wanted to gate the Acao-shape cascade as a whole
5185    /// (a per-`Acao` CR materializer's admission webhook re-checking
5186    /// `:ci` after a per-node patch, a future `feira validate --acao`
5187    /// per-caixa admission verb, a per-`Acao` overlay resolver
5188    /// rejecting an added / renamed node against a cluster-local
5189    /// snapshot) was structurally forced to either re-inline the
5190    /// decompose dispatch in lockstep with the renderer-side wire-up
5191    /// (the duplication the PRIME DIRECTIVE names as a bug) or call
5192    /// the whole [`caixa_actions::validate`] renderer and pay the
5193    /// per-node accumulation to re-check one slot. Post-fold each such
5194    /// consumer reaches the decompose gate through one call on the
5195    /// substrate primitive.
5196    ///
5197    /// Peer to the [`crate::require_acao_view`] compound entry gate
5198    /// every per-`Acao` *renderer* routes through (which already folds
5199    /// the same `require_ci + decompose_ci` two-arm cascade behind its
5200    /// `require_kind` prelude) — this gate mirrors the same fold on
5201    /// the *layout* path, so the two consumers of the Acao-shape
5202    /// cascade (the author-time gate and every per-`Acao` renderer)
5203    /// share one substrate primitive rather than two open-coded
5204    /// cascades kept in lockstep. Same lift discipline the peer
5205    /// per-kind compound gates ([`Self::validate_aplicacao_shape`]
5206    /// 949a7a0, [`Self::validate_supervisor_shape`] 4c70105,
5207    /// [`Self::validate_upgrade_from`] d6801df, [`Self::validate_deps`]
5208    /// b5dd55e, [`Self::validate_limits`] baa4688,
5209    /// [`Self::validate_behavior`] 0d2877a) each carry. Closes the
5210    /// last per-kind asymmetry: with this lift the four typed
5211    /// named-caixa kinds (`Servico` / `Aplicacao` / `Supervisor` /
5212    /// `Acao`) each carry a compound per-`Caixa` shape gate on the
5213    /// substrate, and the layout pipeline routes through the same one
5214    /// substrate primitive per kind rather than four open-coded
5215    /// cascades.
5216    ///
5217    /// # Errors
5218    ///
5219    /// Returns the [`crate::CiDecomposeFailure`] typed view on the
5220    /// present-slot arm — the caixa's `:nome` alongside the borrowed
5221    /// [`canteiro_types::DecomposeError`] source (`DuplicateNode` /
5222    /// `UnknownDep` / `Cycle`) verbatim, so a consumer that fans on
5223    /// the specific arm reaches for `err.source` directly rather than
5224    /// re-parsing the Display bytes. Passes trivially on non-`Acao`
5225    /// kinds and on `:kind Acao` caixas with absent `:ci` (the fold's
5226    /// two identity-element arms).
5227    pub fn validate_acao_shape(&self) -> Result<(), crate::CiDecomposeFailure> {
5228        if !self.kind().is_acao() {
5229            return Ok(());
5230        }
5231        let Some(ci) = self.ci() else {
5232            return Ok(());
5233        };
5234        crate::render::decompose_ci(self, ci).map(|_| ())
5235    }
5236
5237    /// Compound per-`Caixa` kind ↔ typed-slot coherence gate on the
5238    /// three "declared but ignored" typed-slot families — M3 mesh
5239    /// (`:membros` / `:contratos` / `:politicas` / `:placement` /
5240    /// `:entrada`, owned by `:kind Aplicacao`, MESH-COMPOSITION §III.1),
5241    /// supervisor-tree (`:estrategia` / `:max-restarts` /
5242    /// `:restart-window` / `:children`, owned by `:kind Supervisor`,
5243    /// INSPIRATIONS §II.2), and M2 Servico-runtime (`:limits` /
5244    /// `:behavior` / `:upgrade-from`, owned by `:kind Servico`,
5245    /// INSPIRATIONS §III.1 / §II.3 / §II.4). Folds the three sibling
5246    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5247    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5248    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-coherence
5249    /// gates — each pre-lift a self-similar five-line
5250    /// `if !caixa.kind().is_<owner>() { let slots = caixa.declared_
5251    /// <family>_slots(); if !slots.is_empty() { return
5252    /// Err(LayoutError::<family>_on_non_<owner>(caixa, slots)); } }`
5253    /// block at [`crate::layout::StandardLayout::verify`] — onto one
5254    /// substrate primitive on [`Caixa`]. Every arm passes as an
5255    /// identity element on the owner kind (the paired
5256    /// [`Self::kind`] `is_<owner>()` guard short-circuits before the
5257    /// per-family `declared_*_slots` gate fires) and on non-owner
5258    /// kinds carrying no declared slot in that family (the
5259    /// [`Vec::is_empty`] check short-circuits before the wrap fires),
5260    /// so a bare no-code caixa on any kind passes the fold trivially
5261    /// on all three arms.
5262    ///
5263    /// Prior to this lift the three-arm cascade lived only wired
5264    /// open-coded at the layout wire-up site
5265    /// ([`crate::layout::StandardLayout::verify`], caixa-core/src/
5266    /// layout.rs) as three self-similar five-line blocks paired with
5267    /// three [`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
5268    /// [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
5269    /// [`crate::LayoutError::servico_slots_on_non_servico`] ctor
5270    /// dispatches (each of which the peer
5271    /// [`crate::layout::layout_slot_kind_ctors!`] macro already folds
5272    /// onto one substrate primitive per typed variant, 0419438) —
5273    /// every future consumer that wanted to gate the whole
5274    /// kind-coherence cascade as a unit (the deferred
5275    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5276    /// webhook re-checking every typed-slot family after a per-slot
5277    /// patch, a future `feira validate --kind-coherence` per-caixa
5278    /// admission verb, a per-`Caixa` overlay resolver rejecting a
5279    /// kind-foreign patch against a cluster-local snapshot) was
5280    /// structurally forced to either re-inline the three-block
5281    /// cascade in lockstep with the layout wire-up (the duplication
5282    /// the PRIME DIRECTIVE names as a bug) or call the whole
5283    /// [`crate::layout::StandardLayout::verify`] pipeline and pay
5284    /// every peer per-`Caixa` gate to re-check three slot families.
5285    /// Post-fold each such consumer reaches the three-arm cascade
5286    /// through one call on the substrate primitive.
5287    ///
5288    /// Diagnostic order matches the pre-fold layout wire-up
5289    /// canonical sequence — mesh → supervisor → servico — pinned by
5290    /// the load-bearing
5291    /// `validate_kind_slot_coherence_mesh_arm_fires_before_supervisor_arm`
5292    /// / `_supervisor_arm_fires_before_servico_arm` ordering pins
5293    /// below. The three arms enumerate every typed-slot family the
5294    /// substrate carries whose "declared but ignored" footgun is
5295    /// gated at the layout altitude by a `{ caixa, kind, slots }`
5296    /// wrap variant — the peer
5297    /// [`crate::LayoutError::ForeignCodeSlot`] gate on the
5298    /// code-surface family sits outside this fold because
5299    /// [`Self::declared_foreign_code_slots`] bakes the kind-check
5300    /// into the helper (so the layout wire-up carries no outer
5301    /// `if !caixa.kind().is_<owner>()` guard), and the peer
5302    /// [`crate::LayoutError::CiOnNonAcao`] gate on the `:ci` axis
5303    /// carries a distinct `{ caixa, kind }` wrap shape (no `slots`
5304    /// field — `:ci` is a single `Option` not a `Vec`-of-named-slots)
5305    /// and rides on its own peer substrate primitive
5306    /// [`Self::validate_ci_kind_coherence`] (the direct sibling to
5307    /// this fold on the `:ci` axis) — the two folds share the same
5308    /// altitude and diagnostic order at the layout wire-up site but
5309    /// keep their distinct envelope shapes, so no consumer of
5310    /// `CiOnNonAcao` sees a variant rename.
5311    ///
5312    /// Peer to the per-kind compound entry gates every substrate
5313    /// primitive on the M2/M3 typed-slot family already carries
5314    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5315    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5316    /// [`Self::validate_upgrade_from`] d6801df,
5317    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5318    /// [`Self::validate_supervisor_shape`] 4c70105,
5319    /// [`Self::validate_acao_shape`] 5d6df54): the author-time gate
5320    /// axis on the *per-slot* algebra now shares one substrate
5321    /// primitive per compound gate, and this lift closes the
5322    /// symmetric axis on the *cross-family* kind ↔ slot coherence
5323    /// algebra so the layout pipeline routes the three self-similar
5324    /// gates through one substrate primitive rather than three
5325    /// open-coded blocks. Every future kind that adds its own
5326    /// exclusive typed-slot family (an `Actor`-owned per-virtual-
5327    /// actor grain slot the M5 Orleans-inspired kind reaches
5328    /// through, a per-Aplicacao overlay slot the M4 CR materializer
5329    /// consults) folds onto this compound gate as one arm addition
5330    /// rather than a fourth open-coded block at the wire-up site.
5331    ///
5332    /// # Errors
5333    ///
5334    /// Returns the first [`crate::LayoutError`] variant surfacing
5335    /// under the canonical mesh → supervisor → servico order:
5336    /// [`crate::LayoutError::MeshSlotsOnNonAplicacao`] on a non-
5337    /// Aplicacao caixa with a declared M3 mesh slot,
5338    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] on a
5339    /// non-Supervisor caixa with a declared supervisor-tree slot,
5340    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] on a
5341    /// non-Servico caixa with a declared M2 slot. Passes trivially
5342    /// on the owner kind of each family and on non-owner kinds
5343    /// carrying no declared slot in that family (the fold's identity
5344    /// element on both axes).
5345    pub fn validate_kind_slot_coherence(&self) -> Result<(), crate::LayoutError> {
5346        // Each of the three arms routes through the shared
5347        // [`Self::run_kind_owned_slot_family_gate`] substrate primitive
5348        // — the outer non-owner-kind guard + inner accumulator + inner
5349        // emptiness-guard + wrap arm shape now lands on one dispatch
5350        // per family rather than a four-line open-coded block in
5351        // lockstep across all three arms. Canonical mesh → supervisor
5352        // → servico order preserved (the primitive short-circuits
5353        // arm-by-arm; the outer `?;` cascade at this altitude threads
5354        // the first surfaced arm's error verbatim). Each of the three
5355        // ctors ([`crate::LayoutError::mesh_slots_on_non_aplicacao`] /
5356        // [`crate::LayoutError::supervisor_slots_on_non_supervisor`] /
5357        // [`crate::LayoutError::servico_slots_on_non_servico`]) was
5358        // already lifted onto the substrate by the peer
5359        // [`crate::layout::layout_slot_kind_ctors!`] macro, so each arm
5360        // routes through the same substrate-canonical
5361        // `Self::<variant> { caixa, kind, slots }` wrap per arm as the
5362        // pre-lift open-coded blocks — byte-equal, pinned by the
5363        // paired `validate_kind_slot_coherence_folds_<family>_arm_matches_gate`
5364        // equivalence pins and the peer
5365        // `validate_kind_slot_coherence_{mesh,supervisor}_arm_fires_before_<next>_arm`
5366        // ordering pins.
5367        self.run_kind_owned_slot_family_gate(
5368            crate::CaixaKind::is_aplicacao,
5369            Caixa::declared_mesh_slots,
5370            crate::LayoutError::mesh_slots_on_non_aplicacao,
5371        )?;
5372        self.run_kind_owned_slot_family_gate(
5373            crate::CaixaKind::is_supervisor,
5374            Caixa::declared_supervisor_slots,
5375            crate::LayoutError::supervisor_slots_on_non_supervisor,
5376        )?;
5377        self.run_kind_owned_slot_family_gate(
5378            crate::CaixaKind::is_servico,
5379            Caixa::declared_servico_slots,
5380            crate::LayoutError::servico_slots_on_non_servico,
5381        )?;
5382        Ok(())
5383    }
5384
5385    /// Compound per-`Caixa` kind ↔ code-surface coherence gate on
5386    /// the three no-code kinds — `Supervisor` (supervises other
5387    /// caixas, INSPIRATIONS §II.2), `Aplicacao` (composes Servicos,
5388    /// MESH-COMPOSITION §III.1), and `Acao` (owns a typed CI run,
5389    /// CANTEIRO §7.1-C). Each carries no code of its own, so
5390    /// declaring any of `:bibliotecas` / `:exe` / `:servicos`
5391    /// silently passes the layout's path-existence loops (the paths
5392    /// still resolve on disk) and then vanishes downstream — the
5393    /// per-kind renderers gate emission on
5394    /// [`crate::render::require_kind`] and only emit the code
5395    /// surface for its owning kind, so a declared code slot on a
5396    /// no-code kind is the manifest field's documented "ignored
5397    /// otherwise" footgun.
5398    ///
5399    /// Pre-lift each of the three arms lived as a self-similar
5400    /// `if !caixa.kind().is_<no-code-kind>() { … } else if has_code
5401    /// { return Err(LayoutError::<kind>_owns_code(caixa)); }` block
5402    /// at [`crate::layout::StandardLayout::verify`] — three
5403    /// consumers, three identical shapes. Every future consumer
5404    /// that wanted to gate the whole code-surface coherence cascade
5405    /// as a unit (the deferred `caixa.pleme.io/v1alpha1/Caixa` CR
5406    /// materializer's admission webhook re-checking after a
5407    /// per-slot patch, a future `feira validate --no-code-kind`
5408    /// per-caixa admission verb, a per-`Caixa` overlay resolver
5409    /// rejecting a kind-foreign patch) was structurally forced to
5410    /// either re-inline the three-block cascade in lockstep with
5411    /// the layout wire-up (the duplication the PRIME DIRECTIVE
5412    /// names as a bug) or call the whole
5413    /// [`crate::layout::StandardLayout::verify`] pipeline. Post-fold
5414    /// each such consumer reaches the three-arm cascade through
5415    /// one call.
5416    ///
5417    /// Mirror of the sibling [`Self::validate_kind_slot_coherence`]
5418    /// fold (f0d286e) on the author-time typed-slot coherence axis:
5419    /// that gate closes the "non-owner kind declares owner-only
5420    /// typed slots" three-arm cascade on the M2 / supervisor-tree /
5421    /// M3 slot families; this gate closes the reciprocal
5422    /// "no-code kind declares code" three-arm cascade on the
5423    /// `:bibliotecas` / `:exe` / `:servicos` code surface. Together
5424    /// the two folds route every kind ↔ author-shape coherence
5425    /// diagnostic at the layout altitude through one substrate
5426    /// primitive per axis.
5427    ///
5428    /// The gate carries two identity elements:
5429    /// - **`has_code == false`** — any kind (including the three
5430    ///   no-code kinds) that declares no code passes the paired
5431    ///   `!has_code` short-circuit before every per-arm dispatch.
5432    /// - **Code-owning kinds** (`Biblioteca` owning
5433    ///   `:bibliotecas`, `Binario` owning `:exe`, `Servico` owning
5434    ///   `:servicos`) — the three no-code arm-firing predicates
5435    ///   short-circuit on every code-owning kind, so the gate
5436    ///   passes trivially regardless of what code they declare.
5437    ///   Foreign-code-slot violations on a code-owning kind (e.g.
5438    ///   `:kind Servico` declaring `:exe`) surface through the
5439    ///   sibling [`crate::LayoutError::ForeignCodeSlot`] gate on
5440    ///   [`Self::declared_foreign_code_slots`], not through this
5441    ///   gate.
5442    ///
5443    /// Unlike the sibling cross-family
5444    /// [`Self::validate_kind_slot_coherence`], the three arms of
5445    /// this fold are mutually exclusive by construction — `:kind`
5446    /// is a single-valued [`CaixaKind`] discriminator so at most
5447    /// one arm can fire per caixa — and no cross-arm ordering pin
5448    /// is meaningful (the pre-fold three-block cascade at the
5449    /// wire-up site was already unreachable past the first
5450    /// matching arm).
5451    ///
5452    /// Peer to the per-kind compound entry gates every substrate
5453    /// primitive on the M2/M3 typed-slot family already carries
5454    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5455    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5456    /// [`Self::validate_upgrade_from`] d6801df,
5457    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5458    /// [`Self::validate_supervisor_shape`] 4c70105,
5459    /// [`Self::validate_acao_shape`] 5d6df54,
5460    /// [`Self::validate_kind_slot_coherence`] f0d286e): the
5461    /// author-time gate axis on the *per-slot* and *cross-family
5462    /// typed-slot* algebras each share one substrate primitive per
5463    /// compound gate, and this lift closes the third axis on the
5464    /// *code-surface* algebra so the layout pipeline routes all
5465    /// three coherence axes through one substrate primitive rather
5466    /// than nine open-coded blocks. Every future no-code kind
5467    /// (an `Actor` virtual-actor arm the M5 Orleans-inspired kind
5468    /// reaches through if it lands as a no-code composer, a future
5469    /// `Namespace` grouping kind) folds onto this compound gate
5470    /// as one arm addition rather than a fourth open-coded block
5471    /// at the wire-up site.
5472    ///
5473    /// # Errors
5474    ///
5475    /// Returns the [`crate::LayoutError`] variant naming the
5476    /// offending no-code kind:
5477    /// [`crate::LayoutError::SupervisorOwnsCode`] on a `:kind
5478    /// Supervisor` caixa with any declared code,
5479    /// [`crate::LayoutError::AplicacaoOwnsCode`] on a `:kind
5480    /// Aplicacao` caixa with any declared code,
5481    /// [`crate::LayoutError::AcaoOwnsCode`] on a `:kind Acao` caixa
5482    /// with any declared code. Passes trivially on every kind with
5483    /// no declared code and on every code-owning kind regardless
5484    /// of declared code (the fold's two identity-element arms).
5485    pub fn validate_no_code_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5486        let has_code =
5487            !self.bibliotecas().is_empty() || !self.exe().is_empty() || !self.servicos().is_empty();
5488        if !has_code {
5489            return Ok(());
5490        }
5491        if self.kind().is_supervisor() {
5492            return Err(crate::LayoutError::supervisor_owns_code(self));
5493        }
5494        if self.kind().is_aplicacao() {
5495            return Err(crate::LayoutError::aplicacao_owns_code(self));
5496        }
5497        if self.kind().is_acao() {
5498            return Err(crate::LayoutError::acao_owns_code(self));
5499        }
5500        Ok(())
5501    }
5502
5503    /// Compound per-`Caixa` kind ↔ `:ci` coherence gate — the `Acao`
5504    /// axis-only companion to the sibling three-arm
5505    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) on the
5506    /// M3 mesh / supervisor-tree / M2 Servico-runtime typed-slot
5507    /// families. `:ci` carries a typed CI run
5508    /// ([`canteiro_types::CiRun`], CANTEIRO §7.1-C) that only the
5509    /// `caixa-actions` renderer decomposes + validates and only for a
5510    /// `:kind Acao`. On any *other* kind a declared `:ci` is the
5511    /// manifest field's documented "ignored otherwise" — it silently
5512    /// passes verify and then vanishes (never decomposed, never
5513    /// rendered), far from the source `caixa.lisp`.
5514    ///
5515    /// Pre-lift the arm lived as a self-similar
5516    /// `if caixa.ci().is_some() && !caixa.kind().is_acao() { return
5517    /// Err(LayoutError::CiOnNonAcao { caixa: caixa.nome().to_string(),
5518    /// kind: caixa.kind() }); }` block at
5519    /// [`crate::layout::StandardLayout::verify`] — one consumer today
5520    /// but every future consumer that wanted to gate the `:ci`
5521    /// coherence axis as a unit (the deferred
5522    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5523    /// webhook re-checking after a per-slot patch, a future
5524    /// `feira validate --ci-coherence` per-caixa admission verb, a
5525    /// per-`Caixa` overlay resolver rejecting a kind-foreign `:ci`
5526    /// patch) was structurally forced to either re-inline the
5527    /// two-condition guard in lockstep with the layout wire-up (the
5528    /// duplication the PRIME DIRECTIVE names as a bug) or call the
5529    /// whole [`crate::layout::StandardLayout::verify`] pipeline.
5530    /// Post-fold each such consumer reaches the arm through one call.
5531    ///
5532    /// Peer of the sibling three-arm
5533    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) — that
5534    /// gate carries the M3 mesh / supervisor-tree / M2 Servico-runtime
5535    /// axes under a uniform `{ caixa, kind, slots }` envelope
5536    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5537    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5538    /// [`crate::LayoutError::ServicoSlotsOnNonServico`]). The `:ci`
5539    /// axis stays on its own primitive because
5540    /// [`crate::LayoutError::CiOnNonAcao`] carries a distinct
5541    /// `{ caixa, kind }` wrap shape (no `slots` field — `:ci` is a
5542    /// single `Option` not a `Vec`-of-named-slots) whose reshape
5543    /// onto the sibling `{ caixa, kind, slots }` envelope would
5544    /// force a variant rename touching every consumer of
5545    /// `CiOnNonAcao`; the two folds share the same
5546    /// author-time-vs-renderer split and diagnostic altitude, and
5547    /// route through peer substrate primitives on the same
5548    /// [`Caixa`] surface.
5549    ///
5550    /// Peer to the per-kind compound entry gates every substrate
5551    /// primitive on the M2/M3 typed-slot family already carries
5552    /// ([`Self::validate_deps`] b5dd55e, [`Self::validate_limits`]
5553    /// baa4688, [`Self::validate_behavior`] 0d2877a,
5554    /// [`Self::validate_upgrade_from`] d6801df,
5555    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5556    /// [`Self::validate_supervisor_shape`] 4c70105,
5557    /// [`Self::validate_acao_shape`] 5d6df54,
5558    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5559    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2): every
5560    /// author-time coherence axis on the typed [`Caixa`] surface now
5561    /// routes through one substrate primitive per axis rather than
5562    /// an open-coded block at the layout wire-up site.
5563    ///
5564    /// The gate carries two identity elements:
5565    /// - **`ci().is_none()`** — a caixa that declares no `:ci`
5566    ///   passes the first short-circuit before every per-arm
5567    ///   dispatch, on every kind. The canonical shape of the four
5568    ///   non-`Acao` kinds (`Biblioteca` / `Binario` / `Servico` /
5569    ///   `Supervisor` / `Aplicacao`) is `ci = None` — the arm
5570    ///   never fires on a well-shaped fixture.
5571    /// - **`:kind Acao`** — the owner-kind arm short-circuits on
5572    ///   every `Acao` caixa regardless of its `:ci` shape; a
5573    ///   malformed `:ci` on an `Acao` surfaces through the peer
5574    ///   [`Self::validate_acao_shape`] compound decompose gate
5575    ///   (5d6df54), not through this coherence gate.
5576    ///
5577    /// # Errors
5578    ///
5579    /// Returns [`crate::LayoutError::CiOnNonAcao`] naming the
5580    /// offending caixa's nome + kind on any non-`Acao` caixa with
5581    /// `:ci` declared. Passes trivially on every kind that declares
5582    /// no `:ci` and on every `:kind Acao` caixa regardless of
5583    /// declared `:ci` (the fold's two identity-element arms).
5584    pub fn validate_ci_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5585        if self.ci().is_some() && !self.kind().is_acao() {
5586            return Err(crate::LayoutError::CiOnNonAcao {
5587                caixa: self.nome().to_string(),
5588                kind: self.kind(),
5589            });
5590        }
5591        Ok(())
5592    }
5593
5594    /// Compound per-`Caixa` kind ↔ code-surface coherence gate on the
5595    /// two exclusive code-surface slots — `:exe` (owned only by
5596    /// [`crate::CaixaKind::Binario`], the nix-built executable surface)
5597    /// and `:servicos` (owned only by [`crate::CaixaKind::Servico`],
5598    /// the wasm-component + `ComputeUnit` daemon surface). The
5599    /// `caixa-helm` / `caixa-flux` / `caixa-flake` renderers gate
5600    /// emission on [`crate::render::require_kind`]`(_, <owning-kind>)`
5601    /// and only emit the slot for its owning kind — so on any *other*
5602    /// code-running kind a declared `:exe` / `:servicos` is the
5603    /// manifest field's documented "ignored otherwise": the path is
5604    /// validated by the per-kind path-existence loops in
5605    /// [`crate::layout::StandardLayout::verify`], but the value is
5606    /// never rendered into a build target or programs.yaml entry —
5607    /// it silently passes `feira build` and then vanishes, far from
5608    /// the source `caixa.lisp`, with no field naming which slot is
5609    /// foreign.
5610    ///
5611    /// Pre-lift the arm lived as a self-similar four-line `let
5612    /// foreign_code_slots = caixa.declared_foreign_code_slots(); if
5613    /// !foreign_code_slots.is_empty() { return
5614    /// Err(LayoutError::foreign_code_slot(caixa, foreign_code_slots));
5615    /// }` block at [`crate::layout::StandardLayout::verify`] — one
5616    /// consumer today but every future consumer that wanted to gate
5617    /// the code-surface coherence axis as a unit (the deferred
5618    /// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission
5619    /// webhook re-checking after a per-slot patch, a future
5620    /// `feira validate --foreign-code` per-caixa admission verb, a
5621    /// per-`Caixa` overlay resolver rejecting a kind-foreign code-
5622    /// slot patch) was structurally forced to either re-inline the
5623    /// two-condition guard in lockstep with the layout wire-up (the
5624    /// duplication the PRIME DIRECTIVE names as a bug) or call the
5625    /// whole [`crate::layout::StandardLayout::verify`] pipeline.
5626    /// Post-fold each such consumer reaches the arm through one call.
5627    ///
5628    /// Peer of the sibling three-arm
5629    /// [`Self::validate_kind_slot_coherence`] fold (f0d286e) — that
5630    /// gate carries the M3 mesh / supervisor-tree / M2 Servico-runtime
5631    /// axes under the uniform `{ caixa, kind, slots }` envelope
5632    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
5633    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
5634    /// [`crate::LayoutError::ServicoSlotsOnNonServico`]); this gate
5635    /// carries the code-surface axis under the same
5636    /// `{ caixa, kind, slots }` envelope
5637    /// ([`crate::LayoutError::ForeignCodeSlot`]). The two folds share
5638    /// the envelope shape but stay separate primitives because the
5639    /// per-arm predicate differs: the cross-family fold rides on the
5640    /// outer `!self.kind().is_<owner>()` guard *paired* with a
5641    /// per-family `declared_<family>_slots` accumulator, while this
5642    /// fold's per-arm kind-check is baked into
5643    /// [`Self::declared_foreign_code_slots`] itself (each arm's
5644    /// `!self.kind().requires_<slot>()` guard fires inside the
5645    /// accumulator, not around it) — so a `:kind Binario` declaring
5646    /// `:servicos` and a `:kind Servico` declaring `:exe` are both
5647    /// caught by one accumulator sweep rather than by two independent
5648    /// arm dispatches. Peer with [`Self::validate_ci_kind_coherence`]
5649    /// (9b55beb) which carries the `:ci` axis on its own primitive
5650    /// for the same "distinct per-arm predicate shape, shared
5651    /// diagnostic altitude" reason.
5652    ///
5653    /// Peer to the per-kind and per-slot compound entry gates every
5654    /// substrate primitive on the M2/M3 typed-slot family already
5655    /// carries ([`Self::validate_deps`] b5dd55e,
5656    /// [`Self::validate_limits`] baa4688,
5657    /// [`Self::validate_behavior`] 0d2877a,
5658    /// [`Self::validate_upgrade_from`] d6801df,
5659    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5660    /// [`Self::validate_supervisor_shape`] 4c70105,
5661    /// [`Self::validate_acao_shape`] 5d6df54,
5662    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5663    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
5664    /// [`Self::validate_ci_kind_coherence`] 9b55beb): every
5665    /// author-time coherence axis on the typed [`Caixa`] surface now
5666    /// routes through one substrate primitive per axis rather than an
5667    /// open-coded block at the layout wire-up site. This closes the
5668    /// last open-coded kind ↔ slot coherence gate at the layout
5669    /// altitude — every kind-coherence diagnostic is now a substrate
5670    /// primitive.
5671    ///
5672    /// The gate carries three identity elements:
5673    /// - **Code-owning kinds on their native slot** — a
5674    ///   [`crate::CaixaKind::Binario`] declaring `:exe`, a
5675    ///   [`crate::CaixaKind::Servico`] declaring `:servicos` — each
5676    ///   arm's `!requires_<slot>()` predicate short-circuits inside
5677    ///   [`Self::declared_foreign_code_slots`], so the accumulator
5678    ///   returns an empty `Vec` and the outer `is_empty` short-
5679    ///   circuits before the wrap fires.
5680    /// - **Bare caixas** — a caixa with no declared code on any kind
5681    ///   passes the same accumulator's `is_empty` short-circuit on
5682    ///   every arm.
5683    /// - **No-code kinds** ([`crate::CaixaKind::Supervisor`] /
5684    ///   [`crate::CaixaKind::Aplicacao`] / [`crate::CaixaKind::Acao`])
5685    ///   declaring code — dominated upstream by the sibling
5686    ///   [`Self::validate_no_code_kind_coherence`] (3bbf6a2) which
5687    ///   surfaces [`crate::LayoutError::SupervisorOwnsCode`] /
5688    ///   [`crate::LayoutError::AplicacaoOwnsCode`] /
5689    ///   [`crate::LayoutError::AcaoOwnsCode`] first at the layout
5690    ///   wire-up site, so this gate never fires on a no-code kind
5691    ///   through the layout pipeline. A standalone caller reaching
5692    ///   this primitive without the sibling `_no_code_` gate first
5693    ///   would see a no-code kind's declared `:exe` / `:servicos`
5694    ///   surface `ForeignCodeSlot` here (the two folds partition the
5695    ///   diagnostic responsibility along the "declared no-code slot"
5696    ///   axis: no-code kinds get `OwnsCode`, code-running kinds get
5697    ///   `ForeignCodeSlot`), and the layout wire-up's canonical
5698    ///   `_no_code_` → `_foreign_code_` ordering keeps the
5699    ///   [`crate::LayoutError::SupervisorOwnsCode`] / … arm the one
5700    ///   that surfaces in the composed pipeline.
5701    ///
5702    /// Diagnostic order within the arm matches the pre-fold layout
5703    /// wire-up canonical sequence — `:exe` → `:servicos` — pinned by
5704    /// [`Self::declared_foreign_code_slots`]'s per-arm push order.
5705    ///
5706    /// # Errors
5707    ///
5708    /// Returns [`crate::LayoutError::ForeignCodeSlot`] naming the
5709    /// offending caixa's nome + kind + declared foreign-code slot
5710    /// list on any code-running kind ([`crate::CaixaKind::Biblioteca`]
5711    /// / [`crate::CaixaKind::Binario`] / [`crate::CaixaKind::Servico`])
5712    /// declaring another code-running kind's exclusive code surface.
5713    /// Passes trivially on every native-slot declaration (Binario
5714    /// with `:exe`, Servico with `:servicos`), on every bare caixa,
5715    /// and on every no-code kind (dominated upstream by the sibling
5716    /// [`Self::validate_no_code_kind_coherence`] `OwnsCode` gates —
5717    /// see the identity-element notes above).
5718    pub fn validate_foreign_code_kind_coherence(&self) -> Result<(), crate::LayoutError> {
5719        let foreign_code_slots = self.declared_foreign_code_slots();
5720        if !foreign_code_slots.is_empty() {
5721            return Err(crate::LayoutError::foreign_code_slot(
5722                self,
5723                foreign_code_slots,
5724            ));
5725        }
5726        Ok(())
5727    }
5728
5729    /// Compound per-`Caixa` required-slot gate on the three
5730    /// [`crate::CaixaKind`] arms whose sole payload is a canonical
5731    /// typed slot: `Binario`'s `:exe`, `Servico`'s `:servicos`,
5732    /// `Acao`'s `:ci`. Each arm refuses a caixa on its owner kind
5733    /// that declares no value in the corresponding required slot,
5734    /// so `feira build` (the canonical author-time gate) surfaces the
5735    /// self-locating "this kind needs this slot" diagnostic at the
5736    /// source `caixa.lisp` rather than deferring the failure to a
5737    /// downstream consumer (a nix build with no `:exe` to build, a
5738    /// programs.yaml fan-out with no `:servicos` to enumerate, a
5739    /// `caixa-actions` decompose with no `:ci` to walk).
5740    ///
5741    /// Pre-lift each of the three arms lived as a self-similar
5742    /// `if caixa.kind().requires_<slot>() && caixa.<slot>().is_<empty>() {
5743    /// return Err(LayoutError::<kind>_without_<slot>(caixa)); }`
5744    /// block at [`crate::layout::StandardLayout::verify`] — three
5745    /// consumers, three identical shapes, one substrate primitive on
5746    /// [`Caixa`] closing the duplication the PRIME DIRECTIVE names as
5747    /// a bug. Each of the three inner ctors
5748    /// ([`crate::LayoutError::binario_without_exe`] /
5749    /// [`crate::LayoutError::servico_without_servicos`] /
5750    /// [`crate::LayoutError::missing_ci`]) was already lifted onto
5751    /// the substrate by the peer [`crate::layout::layout_nome_only_ctors!`]
5752    /// macro, so the primitive routes through the same
5753    /// `Self::<variant>(caixa.nome().to_string())` tuple-literal
5754    /// wrap per arm as the pre-lift open-coded blocks.
5755    ///
5756    /// The paired `Biblioteca`-arm required-slot check
5757    /// ([`crate::LayoutError::MissingLib`]) stays open-coded at the
5758    /// layout wire-up site by design: it needs the filesystem oracle
5759    /// on [`crate::layout::LayoutInvariants`] to check the default
5760    /// `lib/<nome>.lisp` fallback path, which the pure per-`Caixa`
5761    /// typed-shape surface this fold rides on has no reference to.
5762    /// Same posture the peer [`Self::validate_no_code_kind_coherence`]
5763    /// fold takes on the on-disk existence loops.
5764    ///
5765    /// Diagnostic order at the primitive matches the pre-fold layout
5766    /// wire-up canonical sequence — `:exe` → `:servicos` → `:ci` —
5767    /// the same three-arm sweep the peer [`crate::CaixaKind`]
5768    /// discriminator carries at its `requires_*` accessors. Unlike
5769    /// the sibling cross-family [`Self::validate_kind_slot_coherence`]
5770    /// fold, the three arms of this fold are mutually exclusive by
5771    /// construction — `:kind` is a single-valued [`crate::CaixaKind`]
5772    /// discriminator so at most one arm can fire per caixa — and no
5773    /// cross-arm ordering pin is meaningful (the pre-fold three-block
5774    /// cascade at the wire-up site was already unreachable past the
5775    /// first matching arm).
5776    ///
5777    /// Peer to the per-kind and per-slot compound entry gates every
5778    /// substrate primitive on the M2/M3 typed-slot family already
5779    /// carries ([`Self::validate_deps`] b5dd55e,
5780    /// [`Self::validate_limits`] baa4688,
5781    /// [`Self::validate_behavior`] 0d2877a,
5782    /// [`Self::validate_upgrade_from`] d6801df,
5783    /// [`Self::validate_aplicacao_shape`] 949a7a0,
5784    /// [`Self::validate_supervisor_shape`] 4c70105,
5785    /// [`Self::validate_acao_shape`] 5d6df54,
5786    /// [`Self::validate_kind_slot_coherence`] f0d286e,
5787    /// [`Self::validate_no_code_kind_coherence`] 3bbf6a2,
5788    /// [`Self::validate_ci_kind_coherence`] 9b55beb): every
5789    /// author-time coherence axis on the typed [`Caixa`] surface
5790    /// now routes through one substrate primitive per axis rather
5791    /// than an open-coded block at the layout wire-up site.
5792    ///
5793    /// The gate carries two identity elements:
5794    /// - **Non-owner kinds** — each per-arm predicate is
5795    ///   `self.kind().requires_<slot>()`, which returns `true` only
5796    ///   for the owning kind ([`crate::CaixaKind::Binario`] on `:exe`,
5797    ///   [`crate::CaixaKind::Servico`] on `:servicos`,
5798    ///   [`crate::CaixaKind::Acao`] on `:ci`). Every non-owner kind
5799    ///   passes each per-arm dispatch trivially.
5800    /// - **Owner kinds with the required slot present** — a
5801    ///   [`crate::CaixaKind::Binario`] with a non-empty `:exe`, a
5802    ///   [`crate::CaixaKind::Servico`] with a non-empty `:servicos`,
5803    ///   an [`crate::CaixaKind::Acao`] with `ci = Some(_)` — passes
5804    ///   its arm's `is_empty` / `is_none` short-circuit.
5805    ///
5806    /// # Errors
5807    ///
5808    /// Returns the [`crate::LayoutError`] variant naming the
5809    /// offending owner kind:
5810    /// [`crate::LayoutError::BinarioWithoutExe`] on a
5811    /// [`crate::CaixaKind::Binario`] caixa with no declared `:exe`,
5812    /// [`crate::LayoutError::ServicoWithoutServicos`] on a
5813    /// [`crate::CaixaKind::Servico`] caixa with no declared
5814    /// `:servicos`, [`crate::LayoutError::MissingCi`] on a
5815    /// [`crate::CaixaKind::Acao`] caixa with no declared `:ci`.
5816    /// Passes trivially on every non-owner kind and on every owner
5817    /// kind with its required slot present.
5818    pub fn validate_required_kind_slot(&self) -> Result<(), crate::LayoutError> {
5819        if self.kind().requires_exe() && self.exe().is_empty() {
5820            return Err(crate::LayoutError::binario_without_exe(self));
5821        }
5822        if self.kind().requires_servicos() && self.servicos().is_empty() {
5823            return Err(crate::LayoutError::servico_without_servicos(self));
5824        }
5825        if self.kind().requires_ci() && self.ci().is_none() {
5826            return Err(crate::LayoutError::missing_ci(self));
5827        }
5828        Ok(())
5829    }
5830
5831    /// Reject per-entry values on the three Caixa-level code-surface
5832    /// path lists (`:bibliotecas`, `:exe`, `:servicos`) that the
5833    /// layout checker's `root.join(p)` sandbox would silently subvert.
5834    /// Same three structural footguns the peer
5835    /// [`BehaviorSpec::validate`] (b0c8389) and
5836    /// [`crate::UpgradeInstruction::validate`] `StateChange` arm
5837    /// (26da2c7) already close on the M2 `:behavior :on-*` and
5838    /// `:upgrade-from :state-change :script` axes, here lifted onto
5839    /// the three top-level code-path axes through the shared
5840    /// [`is_sandboxed_relative_path`] predicate:
5841    ///
5842    ///   - empty entry (`(:bibliotecas (""))` / `(:exe (""))` /
5843    ///     `(:servicos (""))`): `PathBuf::new()` round-trips through
5844    ///     [`Path::join`] as the base itself — `root.join("")` ==
5845    ///     `root`, so the existence check (`self.exists(&root)`)
5846    ///     trivially passes (the project root exists), and the layout
5847    ///     silently treats the project root as a biblioteca / exe /
5848    ///     servico entry. The `:bibliotecas` loop then hands the root
5849    ///     to `tatara_lisp::read` at `feira build` time as if the root
5850    ///     directory itself were a Lisp source file — a parse error
5851    ///     far from the source `caixa.lisp` with no field naming the
5852    ///     offending entry.
5853    ///   - absolute path (`(:bibliotecas ("/etc/passwd"))`):
5854    ///     [`Path::join`] *replaces* the base when the right-hand side
5855    ///     is absolute, so `root.join("/etc/passwd")` resolves to
5856    ///     `"/etc/passwd"` and escapes the project sandbox entirely.
5857    ///     The existence check then silently consults whatever the
5858    ///     escaped path resolves to — for `:bibliotecas`, the layout
5859    ///     has no `starts_with`-fence (only `:exe` is fenced under
5860    ///     `exe/` and `:servicos` under `servicos/`), so an absolute
5861    ///     `:bibliotecas` entry that happens to resolve on disk
5862    ///     silently passes. For `:exe` / `:servicos` the fence catches
5863    ///     the absolute case downstream as `ExeOutsideDir` /
5864    ///     `ServicoOutsideDir` (or `MissingEntry` if the absolute path
5865    ///     doesn't exist), but with a downstream-shaped diagnostic
5866    ///     that names the resolved escape path rather than the
5867    ///     authoring footgun at the source.
5868    ///   - parent-escape (`(:bibliotecas ("../sibling/x.lisp"))` /
5869    ///     `(:exe ("exe/../../escape.lisp"))`): a [`PathBuf`] with any
5870    ///     [`std::path::Component::ParentDir`] anywhere round-trips
5871    ///     through [`Path::join`] as a traversal above the caixa root.
5872    ///     The `:exe` / `:servicos` `starts_with(<dir>)` fence is
5873    ///     *component-aware* (not canonical-path-aware), so
5874    ///     `root.join("exe/../../escape.lisp")` `starts_with(exe_dir)`
5875    ///     is **true** even though the canonical resolution
5876    ///     `{parent of root}/escape.lisp` lives outside the caixa root
5877    ///     — the fence silently lets the parent-escape through, and
5878    ///     the existence check passes if that escape-target happens
5879    ///     to exist. Caught regardless of where the `..` sits
5880    ///     (leading, mid-path, trailing) so the gate matches the peer
5881    ///     predicate's full coverage.
5882    ///
5883    /// Same `Empty` → `Absolute` → `ParentEscape` arm-ordering every peer
5884    /// `is_sandboxed_relative_path` consumer follows (b0c8389 / 26da2c7);
5885    /// same per-slot diagnostic shape every peer per-axis path-gate
5886    /// exposes (`*Empty { slot }` / `*Absolute { slot, path }` /
5887    /// `*ParentEscape { slot, path }`). Cross-slot precedence is
5888    /// `:bibliotecas` → `:exe` → `:servicos` — the same declaration
5889    /// order [`Caixa::declared_foreign_code_slots`] uses for its
5890    /// canonical foreign-code-slot diagnostic, so a manifest with
5891    /// multiple malformed slots surfaces the lexicographically-earliest
5892    /// slot's diagnostic deterministically.
5893    ///
5894    /// Lifted to the typed surface as a Caixa-level validator (peer
5895    /// of [`Self::validate_nome`] / [`Self::validate_versao`] /
5896    /// [`Self::validate_deps`] / [`Self::validate_restart_window`])
5897    /// and wired into [`crate::StandardLayout::verify`] before the
5898    /// existence-check loops so the diagnostic names the offending
5899    /// slot at the source caixa.lisp rather than reporting a
5900    /// downstream `MissingEntry` / `ExeOutsideDir` /
5901    /// `ServicoOutsideDir` against the resolved sandbox-escape path.
5902    /// The fourth typed code-path surface — every author-supplied
5903    /// path on the manifest — is now structurally accept-shaped
5904    /// past validate, peer with `:behavior :on-*` and
5905    /// `:upgrade-from :state-change :script`.
5906    pub fn validate_code_paths(&self) -> Result<(), ManifestError> {
5907        /// Per-slot file-type contract for the three Caixa-level
5908        /// code-path surfaces (`:bibliotecas`, `:exe`, `:servicos`).
5909        /// Each variant names the predicate the per-entry file-type
5910        /// gate consults; [`Self::None`] opts the slot out of any
5911        /// file-type contract. Lifted as a typed local enum so the
5912        /// per-slot dispatch is exhaustive at the `match` — adding a
5913        /// future axis to the typed-substrate `:` slot set (the
5914        /// future `:assets` resource axis the M5 roadmap names, the
5915        /// future `:nix-flake` derivation axis the caixa-flake
5916        /// emitter consults) lands as one variant + one `match` arm,
5917        /// not a coordinated rewrite of every per-slot bool flag.
5918        ///
5919        /// Peer of the typed-substrate per-slot variant disciplines
5920        /// already established on this surface
5921        /// ([`crate::supervisor::RestartStrategy`] +
5922        /// [`crate::supervisor::RestartPolicy`] on the OTP-shape
5923        /// supervision-tree axis,
5924        /// [`crate::aplicacao::PlacementStrategy`] on the §III.1
5925        /// placement axis, [`crate::aplicacao::WitTarget`] on the
5926        /// `:contratos` payload-target axis): the typed `enum` is
5927        /// the substrate's single source of truth for the per-axis
5928        /// dispatch, and every consumer (the per-arm body here, the
5929        /// future feira-lint per-slot diagnostic renderer, the M4
5930        /// per-axis admission webhook) reaches for the same typed
5931        /// surface rather than re-deriving the partition from inline
5932        /// flag combinations.
5933        enum CodePathFileType {
5934            /// `:exe` — nix-build derivation output, no terminating-
5935            /// extension contract (the canonical `"exe/<name>"`
5936            /// fixtures the layout's `ExeOutsideDir` error message
5937            /// documents carry no extension by convention).
5938            None,
5939            /// `:bibliotecas` — tatara-lisp source files the
5940            /// `feira build` loop reads through `tatara_lisp::read`
5941            /// at parse time. Routes to [`is_lisp_extension`].
5942            LispSource,
5943            /// `:servicos` — ComputeUnit-CR YAML files the
5944            /// caixa-helm / caixa-flux renderers consume through
5945            /// `serde_yaml::from_str`. Routes to
5946            /// [`is_computeunit_yaml_extension`].
5947            ComputeUnitYaml,
5948        }
5949
5950        // The per-slot [`CodePathFileType`] selects which axes carry the
5951        // lifted file-type predicate. `:bibliotecas` is the tatara-lisp
5952        // source axis (the `feira build` loop at
5953        // `caixa-feira/src/cmd/build.rs:33` reads each entry through
5954        // `tatara_lisp::read` at parse time) — the lifted
5955        // [`is_lisp_extension`] predicate gates the `.lisp` extension.
5956        // `:exe` is the nix-built executable surface (per the canonical
5957        // `"exe/<name>"`-shaped fixtures the layout's `ExeOutsideDir`
5958        // error message documents and every in-tree
5959        // `caixa_with_code_paths` positive control uses) — its file-type
5960        // contract is "nix-build derivation output", not a typed source
5961        // file, so [`CodePathFileType::None`] opts the slot out of any
5962        // file-type gate. `:servicos` is the `.computeunit.yaml`
5963        // ComputeUnit-CR axis (the peer caixa-helm / caixa-flux
5964        // renderers consume each entry through `serde_yaml::from_str` as
5965        // a typed `ComputeUnit` CR) — the lifted
5966        // [`is_computeunit_yaml_extension`] predicate gates the compound
5967        // `.computeunit.yaml` suffix. All three axes are surfaced through
5968        // the same iteration so the sandbox-shape + duplicate gates
5969        // apply uniformly; the typed file-type dispatch fires per-slot
5970        // exactly where the downstream consumer's accepted set demands
5971        // it. The third file-type variant ([`ComputeUnitYaml`]) is the
5972        // compounding lift on the peer 64772a9 `:bibliotecas`
5973        // `.lisp`-gate trajectory — the second of the three code-path
5974        // axes to land on a typed compound-suffix gate, with the same
5975        // self-locating per-slot diagnostic shape every peer per-axis
5976        // file-type lift uses (`*NonLispExtension { slot, path }` /
5977        // `*NonComputeUnitYamlExtension { slot, path }`).
5978        for (slot, list, file_type) in [
5979            (
5980                ":bibliotecas",
5981                &self.bibliotecas,
5982                CodePathFileType::LispSource,
5983            ),
5984            (":exe", &self.exe, CodePathFileType::None),
5985            (
5986                ":servicos",
5987                &self.servicos,
5988                CodePathFileType::ComputeUnitYaml,
5989            ),
5990        ] {
5991            // Per-slot set-not-multiset gate on the typed code-path axis.
5992            // Every peer Vec-shaped author-supplied list past validate is
5993            // a set, not a multiset: `:membros :caixa`
5994            // ([`crate::AplicacaoError::MembroDuplicate`]), `:placement
5995            // :clusters` ([`crate::AplicacaoError::PlacementClusterDuplicate`]),
5996            // `:entrada :paths` ([`crate::AplicacaoError::EntradaPathDuplicate`]),
5997            // `:contratos` ([`crate::AplicacaoError::ContratoDuplicate`]),
5998            // `:children :caixa` ([`crate::SupervisorError::DuplicateChild`]),
5999            // `:deps` / `:deps-dev` `:nome` ([`crate::DepError::DuplicateNome`]
6000            // per 359fba5), `:upgrade-from :from` ([`crate::UpgradeError::DuplicateFrom`]),
6001            // `:etiquetas` ([`ManifestError::EtiquetaDuplicate`] per 360a499),
6002            // `:autores` ([`ManifestError::AutorDuplicate`] per 86c769b) —
6003            // the three code-path lists are the last Vec-shaped author-
6004            // supplied slots on the typed Caixa surface still admitting a
6005            // duplicate entry silently. Scope is per-list (`:bibliotecas`
6006            // duplicates are flagged within `:bibliotecas`, not across
6007            // `:bibliotecas` ↔ `:exe`) — the same per-list scope `:deps`
6008            // ↔ `:deps-dev` use (a `:nome` present in both lists is a
6009            // legitimate dev-vs-runtime shape on the dep axis, fenced
6010            // separately by [`crate::dep::validate_no_self_dep`]). On the
6011            // code-path axis a cross-slot collision is structurally
6012            // impossible by the layout's `starts_with(<exe|servicos>_dir)`
6013            // fence — `:exe` and `:servicos` entries are confined to their
6014            // own directory trees, so the only way a string could appear
6015            // on two code-path lists is the (rare, structurally invalid)
6016            // case where `:bibliotecas` carries an `"exe/<x>"` or
6017            // `"servicos/<x>.yaml"`-shaped path.
6018            //
6019            // Without the gate three authoring footguns silently passed:
6020            //
6021            //   - `:bibliotecas ("lib/foo.lisp" "lib/foo.lisp")` — the
6022            //     canonical copy-paste-the-wrong-file footgun. `feira
6023            //     build` (`caixa-feira/src/cmd/build.rs:33`) walks the
6024            //     list and re-parses the same file twice, wasting work
6025            //     and silently masking the author's intent to declare a
6026            //     *second* biblioteca.
6027            //   - `:exe ("exe/cli" "exe/cli")` — the same footgun on the
6028            //     Binario surface. The future `caixa-flake` `nix flake`
6029            //     emitter that materializes each `:exe` entry as a flake
6030            //     `packages.<exe-name>` derivation would collide on the
6031            //     duplicate package name and surface a flake-eval error
6032            //     far from the source `caixa.lisp`.
6033            //   - `:servicos ("servicos/x.computeunit.yaml"
6034            //     "servicos/x.computeunit.yaml")` — the same footgun on
6035            //     the Servico surface. The peer `caixa-helm` / `caixa-flux`
6036            //     renderers already refuse `:servicos.len() != 1` with
6037            //     the narrower [`UnsupportedServicoCount`] diagnostic, but
6038            //     that diagnostic surfaces "too many servicos" without
6039            //     naming "duplicate entry" — the typed self-locating
6040            //     "which entry is the duplicate" framing only lands at
6041            //     this gate.
6042            //
6043            // Same `seen.insert(entry.as_str())` shape every peer per-list
6044            // duplicate gate uses (`:etiquetas` 360a499, `:autores`
6045            // 86c769b, `:deps` 359fba5) and the same "structural shape
6046            // checks fire before the duplicate check on the same entry"
6047            // ordering (a `(:bibliotecas ("" "lib/x.lisp" "lib/x.lisp"))`
6048            // shape surfaces the narrower [`Self::CodePathEmpty`] for the
6049            // empty entry first, not the duplicate on the later pair).
6050            let mut seen = std::collections::HashSet::new();
6051            for entry in list {
6052                let path = Path::new(entry);
6053                match is_sandboxed_relative_path(path) {
6054                    Ok(()) => {}
6055                    Err(PathShapeViolation::Empty) => {
6056                        return Err(ManifestError::code_path_empty(slot));
6057                    }
6058                    Err(PathShapeViolation::Absolute) => {
6059                        return Err(ManifestError::code_path_absolute(slot, path));
6060                    }
6061                    Err(PathShapeViolation::ParentEscape) => {
6062                        return Err(ManifestError::code_path_parent_escape(slot, path));
6063                    }
6064                }
6065                // The per-slot file-type gate dispatched through the
6066                // typed [`CodePathFileType`] selector above. Each variant
6067                // routes to the lifted predicate the downstream consumer
6068                // demands:
6069                //
6070                //   - [`LispSource`] → [`is_lisp_extension`] for
6071                //     `:bibliotecas` (the `feira build` loop's
6072                //     `tatara_lisp::read` consumer);
6073                //   - [`ComputeUnitYaml`] → [`is_computeunit_yaml_extension`]
6074                //     for `:servicos` (the caixa-helm / caixa-flux
6075                //     `serde_yaml::from_str` consumer's `ComputeUnit` CR
6076                //     accepted set);
6077                //   - [`None`] for `:exe` — the nix-build derivation-
6078                //     output axis has no terminating-extension contract.
6079                //
6080                // Fires after the sandbox-shape arms so a path that is
6081                // *both* sandbox-escaping and wrong-extension surfaces
6082                // the more fundamental sandbox-shape diagnostic first
6083                // (mirrors the peer `EmptyPath` → `AbsolutePath` →
6084                // `ParentEscape` → `NonLispExtension` arm-ordering on
6085                // `:behavior :on-*` c97815a, and `EmptyScript` →
6086                // `AbsoluteScript` → `ParentEscapeScript` →
6087                // `NonLispExtensionScript` on
6088                // `:upgrade-from :state-change :script` 33cc830), and
6089                // before the duplicate gate so the narrower per-entry
6090                // file-type shape dominates the cross-entry uniqueness
6091                // diagnostic (a
6092                // `("servicos/x.yaml" "servicos/x.yaml")` shape on
6093                // `:servicos` surfaces
6094                // `CodePathNonComputeUnitYamlExtension` on the first
6095                // entry rather than `CodePathDuplicate` on the pair —
6096                // peer with the 64772a9 `:bibliotecas`
6097                // `("lib/x.txt" "lib/x.txt")` ordering).
6098                match file_type {
6099                    CodePathFileType::None => {}
6100                    CodePathFileType::LispSource => {
6101                        if !is_lisp_extension(path) {
6102                            return Err(ManifestError::code_path_non_lisp_extension(slot, path));
6103                        }
6104                    }
6105                    CodePathFileType::ComputeUnitYaml => {
6106                        if !is_computeunit_yaml_extension(path) {
6107                            return Err(ManifestError::code_path_non_computeunit_yaml_extension(
6108                                slot, path,
6109                            ));
6110                        }
6111                    }
6112                }
6113                crate::render::insert_first_seen(&mut seen, entry.as_str(), || {
6114                    ManifestError::code_path_duplicate(slot, path)
6115                })?;
6116            }
6117        }
6118        Ok(())
6119    }
6120
6121    /// Reject `:etiquetas` lists with an empty entry or with two entries
6122    /// agreeing on the same string. `:etiquetas` is the universal
6123    /// registry-search-tag axis on [`Caixa`] (every kind carries the
6124    /// `Vec<String>` slot) and lands verbatim as the Helm chart
6125    /// `Chart.yaml` `keywords:` array on every Servico (caixa-helm's
6126    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:236` folds it through
6127    /// a [`std::collections::BTreeSet`] alongside the four substrate-
6128    /// fixed tags `lareira` / `wasm` / `tatara-lisp` / `caixa-servico`).
6129    /// Two authoring footguns silently passed validate without this gate:
6130    ///
6131    ///   - Empty entry (`(:etiquetas (""))` — the canonical paste-from-
6132    ///     blank-doc footgun) rendered as `keywords: ["", "caixa-servico",
6133    ///     "lareira", "tatara-lisp", "wasm"]` in `Chart.yaml`. Helm's
6134    ///     `chart.metadata.keywords` admits the value without a strict
6135    ///     parser-side gate, but the empty keyword has no operational
6136    ///     meaning — it indexes nothing in the future caixa-registry
6137    ///     search axis and clutters the rendered chart with a no-op tag.
6138    ///   - Duplicate entries (`(:etiquetas ("demo" "demo"))` — the
6139    ///     copy-paste-the-wrong-tag footgun) silently passed validate
6140    ///     and were silently dedup'd by caixa-helm's `BTreeSet` collect
6141    ///     at chart render — a "second wins / one silently disappears"
6142    ///     shape divergent from every peer typed-graph set gate
6143    ///     ([`crate::AplicacaoError::MembroDuplicate`] on `:membros`,
6144    ///     [`crate::AplicacaoError::PlacementClusterDuplicate`] on
6145    ///     `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
6146    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
6147    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
6148    ///     `:deps` / `:deps-dev` per 359fba5, [`crate::UpgradeError::DuplicateFrom`]
6149    ///     on `:upgrade-from`, the per-instruction-class singularity
6150    ///     gates [`crate::UpgradeError::DuplicateLoadModule`] /
6151    ///     [`crate::UpgradeError::DuplicateStateChange`] /
6152    ///     [`crate::UpgradeError::DuplicateCleanup`]). The typed-graph
6153    ///     discipline is uniform: every Vec-shaped author-supplied list
6154    ///     past validate is set-not-multiset, by construction.
6155    ///
6156    /// Past the empty arm the gate enforces the chart-keyword shape
6157    /// predicate via [`crate::render::is_chart_keyword_shape`]: Cargo's
6158    /// crates.io `[package] keywords` grammar — 1..=20 bytes, starts
6159    /// with an ASCII letter, ASCII alphanumeric / `_` / `-`
6160    /// continuation. Closes the canonical paste-from-doc footguns the
6161    /// bare empty + duplicate arms left open: paste-from-aligned-doc
6162    /// whitespace (`" mesh"`, `"mesh "`), paste-from-multiline-doc
6163    /// newline (`"mesh\nhttp"` — the author pasted a multi-tag block
6164    /// into one entry instead of splitting), paste-from-Windows-CRLF-doc
6165    /// carriage return, CSV-list-separator confusion (`"mesh,http,grpc"`
6166    /// — the author meant three separate list entries), path-separator
6167    /// confusion (`"caixa/servico"`), namespace-suffix (`"http.1"`),
6168    /// leading-digit (`"1foo"`), kebab-leak (`"-foo"`), snake-leak
6169    /// (`"_foo"`), non-ASCII (`"café"`), and paste-from-binary-blob
6170    /// control bytes that would silently land as malformed search tags
6171    /// in the rendered Chart.yaml `keywords:` array and break the
6172    /// Artifact Hub keyword index lookup far from the source caixa.lisp.
6173    /// Mirrors the [`Self::validate_autores`] shape-predicate cascade
6174    /// established on the sibling universal-axis `Vec<String>` surface
6175    /// — the second universal-axis Vec<String> surface to land the
6176    /// empty-first-then-shape-then-duplicate per-entry cascade.
6177    ///
6178    /// Same empty-first cascade discipline every peer per-axis gate
6179    /// uses: the per-entry empty arm fires before the per-entry shape
6180    /// arm fires before the cross-entry duplicate arm, so an
6181    /// `("" "mesh" "mesh")` authoring shape surfaces the narrower
6182    /// [`ManifestError::EtiquetaEmpty`] (the structural "this entry
6183    /// has no value" defect) before either the shape or the duplicate
6184    /// diagnostic. Walks the list in declaration order so the
6185    /// first-collision diagnostic surfaces the lexicographically-
6186    /// earliest offending position, peer with every other duplicate
6187    /// gate on this surface.
6188    ///
6189    /// Universal-axis (every kind carries `:etiquetas`), so wired at the
6190    /// caixa-build gate alongside the peer universal gates
6191    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6192    /// [`Self::validate_deps`] / [`Self::validate_code_paths`] — before
6193    /// the kind-coherence gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]
6194    /// / [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6195    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6196    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
6197    /// slot sets. The future caixa-registry search axis can reach for
6198    /// `caixa.etiquetas` knowing every entry is a non-empty distinct
6199    /// chart-keyword-shaped string without re-deriving the precondition.
6200    pub fn validate_etiquetas(&self) -> Result<(), ManifestError> {
6201        let mut seen = std::collections::HashSet::new();
6202        for etiqueta in self.etiquetas() {
6203            if etiqueta.is_empty() {
6204                return Err(ManifestError::EtiquetaEmpty);
6205            }
6206            crate::render::is_chart_keyword_shape(etiqueta)
6207                .map_err(|reason| ManifestError::etiqueta_invalid(etiqueta, reason))?;
6208            crate::render::insert_first_seen(&mut seen, etiqueta.as_str(), || {
6209                ManifestError::etiqueta_duplicate(etiqueta)
6210            })?;
6211        }
6212        Ok(())
6213    }
6214
6215    /// Reject `:autores` lists with an empty entry or with two entries
6216    /// agreeing on the same string. `:autores` is the universal
6217    /// maintainer-axis on [`Caixa`] (every kind carries the
6218    /// `Vec<String>` slot) and lands verbatim as the Helm chart
6219    /// `Chart.yaml` `maintainers:` array on every Servico (caixa-helm's
6220    /// `build_chart_yaml` at `caixa-helm/src/lib.rs:251` maps each entry
6221    /// to a `Maintainer { name, email: None }` without dedup). Two
6222    /// authoring footguns silently passed validate without this gate:
6223    ///
6224    ///   - Empty entry (`(:autores (""))` — the canonical paste-from-
6225    ///     blank-doc footgun) rendered as
6226    ///     `maintainers: [{name: "", email: null}]` in `Chart.yaml`. The
6227    ///     empty maintainer name has no operational meaning — it
6228    ///     identifies no one in the substrate's authorship index and
6229    ///     clutters the rendered chart with a no-op maintainer.
6230    ///   - Duplicate entries (`(:autores ("pleme-io" "pleme-io"))` —
6231    ///     the copy-paste-the-wrong-author footgun) silently passed
6232    ///     validate and rendered as two identical maintainer entries.
6233    ///     Unlike the [`Self::validate_etiquetas`] peer (caixa-helm's
6234    ///     `BTreeSet`-collect on `:etiquetas` silently dedups the
6235    ///     rendered `keywords:` array at chart-render time), the
6236    ///     `maintainers:` rendering has *no* dedup — duplicate `:autores`
6237    ///     entries stack verbatim in the chart, divergent from every
6238    ///     peer typed-graph set gate ([`crate::AplicacaoError::MembroDuplicate`]
6239    ///     on `:membros`, [`crate::AplicacaoError::PlacementClusterDuplicate`]
6240    ///     on `:placement :clusters`, [`crate::AplicacaoError::EntradaPathDuplicate`]
6241    ///     on `:entrada :paths`, [`crate::AplicacaoError::ContratoDuplicate`]
6242    ///     on `:contratos`, [`crate::DepError::DuplicateNome`] on
6243    ///     `:deps` / `:deps-dev`, [`crate::UpgradeError::DuplicateFrom`]
6244    ///     on `:upgrade-from`, [`ManifestError::EtiquetaDuplicate`] on
6245    ///     `:etiquetas`).
6246    ///
6247    /// Past the empty arm the gate enforces the chart-maintainer-name
6248    /// shape predicate via [`crate::render::is_chart_maintainer_name_shape`]:
6249    /// the structural single-line printable-UTF-8 floor every realistic
6250    /// Helm chart maintainer name carries — 1..=128 bytes, no leading
6251    /// or trailing whitespace, no ASCII control characters anywhere,
6252    /// Unicode bytes accepted. Closes the canonical paste-from-doc
6253    /// footguns the bare empty + duplicate arms left open:
6254    /// paste-from-aligned-doc whitespace (`" pleme-io"`, `"pleme-io "`),
6255    /// paste-from-multiline-doc newline (`"alice\nbob"` — the author
6256    /// pasted a multi-line block of author records into one `:autores`
6257    /// entry instead of splitting into one entry per author),
6258    /// paste-from-Windows-CRLF-doc carriage return, tab-from-aligned-doc,
6259    /// and the paste-from-binary-blob control bytes that would silently
6260    /// land as YAML-illegal byte sequences in the rendered Chart.yaml
6261    /// `maintainers:` array. Mirrors the shape-predicate cascade
6262    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
6263    /// [`Self::validate_edicao`] / [`Self::validate_repositorio`]
6264    /// establish past their own empty arms on the sibling universal-axis
6265    /// `Option<String>` surfaces — the first universal-axis Vec<String>
6266    /// surface to land the empty-first-then-shape-then-duplicate per-entry
6267    /// cascade.
6268    ///
6269    /// Same empty-first cascade discipline every peer per-axis gate
6270    /// uses: the per-entry empty arm fires before the per-entry shape
6271    /// arm before the cross-entry duplicate arm. Walks the list in
6272    /// declaration order so the first-collision diagnostic surfaces the
6273    /// lexicographically-earliest offending position, peer with every
6274    /// other duplicate gate on this surface.
6275    ///
6276    /// Universal-axis (every kind carries `:autores`), so wired at the
6277    /// caixa-build gate alongside the peer universal gates
6278    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6279    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6280    /// [`Self::validate_code_paths`] — before the kind-coherence gates
6281    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6282    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6283    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6284    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-specific
6285    /// slot sets.
6286    pub fn validate_autores(&self) -> Result<(), ManifestError> {
6287        let mut seen = std::collections::HashSet::new();
6288        for autor in self.autores() {
6289            if autor.is_empty() {
6290                return Err(ManifestError::AutorEmpty);
6291            }
6292            crate::render::is_chart_maintainer_name_shape(autor)
6293                .map_err(|reason| ManifestError::autor_invalid(autor, reason))?;
6294            crate::render::insert_first_seen(&mut seen, autor.as_str(), || {
6295                ManifestError::autor_duplicate(autor)
6296            })?;
6297        }
6298        Ok(())
6299    }
6300
6301    /// Reject `:repositorio` values whose shape the shared
6302    /// [`crate::render::is_git_repo_url`] predicate refuses. The flat
6303    /// `repositorio: Option<String>` slot on [`Caixa`] is the
6304    /// universal git-shaped homepage axis every kind carries — the
6305    /// substrate routes the same string through two load-bearing
6306    /// consumers:
6307    ///
6308    ///   - [`caixa-helm`] folds it verbatim into the rendered
6309    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `home:` field
6310    ///     (`build_chart_yaml` at `caixa-helm/src/lib.rs:268`) and into
6311    ///     the chart `README.md` `repo = …` interpolation
6312    ///     (`caixa-helm/src/lib.rs:359`).
6313    ///   - [`caixa-flux`] folds it verbatim into the standalone
6314    ///     `ClusterBundleOpts::for_caixa` `git_url:` field
6315    ///     (`caixa-flux/src/lib.rs:293`), which becomes the `FluxCD`
6316    ///     `GitRepository.spec.url` the cluster's source-controller
6317    ///     polls — the load-bearing deploy-time axis.
6318    ///
6319    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
6320    /// substitute a placeholder when the slot is absent (`None` → the
6321    /// fallback fires); a `Some("")` *skips the fallback* and silently
6322    /// passes the empty string through to `Chart.yaml home: ""` /
6323    /// `GitRepository url: ""` — Helm's chart lint and `FluxCD`'s source
6324    /// controller both reject the empty URL far from the source
6325    /// `caixa.lisp`, with no field naming the offending `:repositorio`.
6326    /// Similarly a malformed `:repositorio` (whitespace, control char,
6327    /// missing `:` separator, leading `-`) silently lands in the
6328    /// rendered artifacts and breaks at `git clone` / `helm template`
6329    /// / `flux reconcile` time.
6330    ///
6331    /// Thin wrapper around [`crate::render::is_git_repo_url`] — the
6332    /// same shared predicate the peer [`crate::DepSource::validate`]
6333    /// routes the `:fonte (:tipo git :repo …)` axis through. With this
6334    /// gate the two `git URL`-shaped surfaces on the typed Caixa
6335    /// (`:repositorio` here, `:deps :fonte :repo` peer) are
6336    /// structurally equivalent: every value past validate is
6337    /// guaranteed-acceptable by the predicate's union of constraints
6338    /// (non-empty, length-bounded, no leading `-`, no whitespace, no
6339    /// control chars, ASCII only, no leading `:`, contains a `:`
6340    /// separator). The predicate accepts every documented authoring
6341    /// shape — `github:org/repo` shorthand, `https://host/path`,
6342    /// `ssh://[user@]host/path`, `git://host/path`, `git@host:path`
6343    /// scp-style SSH, `file:///path` — and refuses the canonical
6344    /// paste-from-blank-doc / paste-from-multiline-doc / CLI-arg-
6345    /// injection footguns at validate time. Maps the predicate's
6346    /// `String` reason verbatim into the
6347    /// [`ManifestError::RepositorioInvalid`] variant, carrying the
6348    /// offending value + parser-shaped reason so the diagnostic is
6349    /// self-locating (the author can grep their `caixa.lisp` for
6350    /// `:repositorio "<value>"` and fix it in one edit).
6351    ///
6352    /// `None` (the canonical "omit the slot to express no published
6353    /// homepage" shape) is accepted trivially — the gate is a no-op
6354    /// when the author didn't declare a value. `Some("")` is gated by
6355    /// the narrower [`ManifestError::RepositorioEmpty`] arm before the
6356    /// shape predicate is consulted, mirroring the empty-first cascade
6357    /// every peer per-axis identity gate uses
6358    /// ([`ManifestError::NomeEmpty`] → [`ManifestError::NomeInvalid`],
6359    /// [`ManifestError::VersaoEmpty`] → [`ManifestError::VersaoInvalid`],
6360    /// [`crate::DepError::FonteRepoEmpty`] →
6361    /// [`crate::DepError::FonteRepoInvalid`]).
6362    ///
6363    /// Universal-axis (every kind carries `:repositorio`), so wired at
6364    /// the caixa-build gate alongside the peer universal gates
6365    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6366    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6367    /// [`Self::validate_autores`] / [`Self::validate_code_paths`] —
6368    /// before the kind-coherence gates
6369    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6370    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6371    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6372    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6373    /// specific slot sets.
6374    pub fn validate_repositorio(&self) -> Result<(), ManifestError> {
6375        let Some(s) = self.repositorio() else {
6376            return Ok(());
6377        };
6378        if s.is_empty() {
6379            return Err(ManifestError::RepositorioEmpty);
6380        }
6381        is_git_repo_url(s).map_err(|reason| ManifestError::repositorio_invalid(s, reason))
6382    }
6383
6384    /// Reject `:descricao` values that are the empty string. The flat
6385    /// `descricao: Option<String>` slot on [`Caixa`] is the universal
6386    /// free-form-prose homepage axis every kind carries — the
6387    /// substrate routes the same string through two load-bearing
6388    /// consumers in the [`caixa-helm`] renderer:
6389    ///
6390    ///   - `build_chart_yaml` folds it verbatim into the rendered
6391    ///     `lareira-<nome>` Helm chart's `Chart.yaml` `description:`
6392    ///     field (`caixa-helm/src/lib.rs:232-235`).
6393    ///   - `build_readme` folds it verbatim into the rendered chart
6394    ///     `README.md` header (`caixa-helm/src/lib.rs:333-336`).
6395    ///
6396    /// Both consumers use `Option::unwrap_or_else(|| <fallback>)` to
6397    /// substitute a `caixa.nome`-derived placeholder when the slot is
6398    /// absent (`None` → the fallback fires); a `Some("")` *skips the
6399    /// fallback* and silently passes the empty string through to
6400    /// `Chart.yaml description: ""` / a blank chart `README.md`
6401    /// header. Helm's chart spec requires a non-empty `description:`
6402    /// field on `apiVersion: v2` charts (`helm lint` surfaces it as
6403    /// `WARNING [chart.metadata.description]: description is required`),
6404    /// so the empty `Some("")` silently lands in the rendered
6405    /// artifacts and breaks at `helm lint` / `helm install` time far
6406    /// from the source `caixa.lisp`, with no field naming the
6407    /// offending `:descricao`.
6408    ///
6409    /// `None` (the canonical "omit the slot to defer to the renderer's
6410    /// `caixa.nome`-derived fallback" shape) is accepted trivially —
6411    /// the gate is a no-op when the author didn't declare a value.
6412    /// `Some("")` is gated by the narrower
6413    /// [`ManifestError::DescricaoEmpty`] arm, mirroring the empty-arm
6414    /// shape every peer per-axis empty gate uses
6415    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6416    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6417    /// [`ManifestError::RepositorioEmpty`]).
6418    ///
6419    /// Universal-axis (every kind carries `:descricao`), so wired at
6420    /// the caixa-build gate alongside the peer universal gates
6421    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6422    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6423    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6424    /// [`Self::validate_code_paths`] — before the kind-coherence
6425    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6426    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6427    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6428    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6429    /// specific slot sets.
6430    ///
6431    /// Past the empty arm the gate enforces the chart-description
6432    /// shape predicate via [`crate::render::is_chart_description_shape`]:
6433    /// the structural single-line UTF-8 floor every realistic chart
6434    /// description in the wild matches — 1..=512 bytes, no leading
6435    /// or trailing whitespace, no ASCII control characters anywhere
6436    /// (`0x00..=0x1F` plus `0x7F` DEL — banning tab, newline,
6437    /// carriage return, and every other control byte), Unicode
6438    /// continuation bytes accepted (the canonical fixtures carry
6439    /// `→` and `—`). Closes the canonical paste-from-doc footguns
6440    /// the bare empty-arm gate left open: paste-from-aligned-doc
6441    /// leading / trailing whitespace (`" Checkout flow."`,
6442    /// `"Checkout flow. "`), paste-from-multiline-doc newline
6443    /// (`"Checkout\nflow."`), paste-from-Windows-CRLF-doc CR
6444    /// (`"Checkout\rflow."`), tab-from-aligned-doc
6445    /// (`"Checkout\tflow."`), and paste-from-binary-blob NUL / BEL /
6446    /// ESC / DEL bytes. Mirrors the shape-predicate cascade
6447    /// [`Self::validate_repositorio`] / [`Self::validate_licenca`] /
6448    /// [`Self::validate_edicao`] establish past their own empty arms
6449    /// on the sibling universal-axis `Option<String>` Caixa-level
6450    /// value-shape surfaces.
6451    ///
6452    /// The empty-first cascade discipline mirrors every peer per-axis
6453    /// identity gate: [`ManifestError::DescricaoEmpty`] runs before
6454    /// [`ManifestError::DescricaoInvalid`], so the narrower empty
6455    /// diagnostic surfaces on `Some("")` rather than the broader
6456    /// shape-predicate diagnostic — peer with how
6457    /// [`ManifestError::LicencaEmpty`] runs before
6458    /// [`ManifestError::LicencaInvalid`],
6459    /// [`ManifestError::EdicaoEmpty`] runs before
6460    /// [`ManifestError::EdicaoInvalid`],
6461    /// [`ManifestError::RepositorioEmpty`] runs before
6462    /// [`ManifestError::RepositorioInvalid`].
6463    pub fn validate_descricao(&self) -> Result<(), ManifestError> {
6464        let Some(s) = self.descricao() else {
6465            return Ok(());
6466        };
6467        if s.is_empty() {
6468            return Err(ManifestError::DescricaoEmpty);
6469        }
6470        crate::render::is_chart_description_shape(s)
6471            .map_err(|reason| ManifestError::descricao_invalid(s, reason))?;
6472        Ok(())
6473    }
6474
6475    /// Reject `:licenca` values that are the empty string. The flat
6476    /// `licenca: Option<String>` slot on [`Caixa`] is the universal
6477    /// SPDX-shaped license-expression axis every kind carries — the
6478    /// substrate routes the same string through the [`caixa-helm`]
6479    /// renderer's `build_readme` which folds it verbatim into the
6480    /// rendered `lareira-<nome>` Helm chart's `README.md` `## License`
6481    /// section (`caixa-helm/src/lib.rs:361`) via
6482    /// `caixa.licenca.clone().unwrap_or_else(|| "MIT".into())`. The
6483    /// fallback only fires on `None`; a `Some("")` *skips the
6484    /// fallback* and silently passes the empty string through to a
6485    /// chart `README.md` whose `License` section renders as the bare
6486    /// trailing period (`.\n`) — peer footgun with the
6487    /// `Some("")`-skips-`unwrap_or_else` shape the
6488    /// [`Self::validate_descricao`] and [`Self::validate_repositorio`]
6489    /// gates close on the sibling free-form-prose and git-URL axes.
6490    ///
6491    /// `None` (the canonical "omit the slot to defer to the
6492    /// renderer's `MIT` fallback" shape every existing fixture
6493    /// carries) is accepted trivially — the gate is a no-op when the
6494    /// author didn't declare a value. `Some("")` is gated by the
6495    /// narrower [`ManifestError::LicencaEmpty`] arm, mirroring the
6496    /// empty-arm shape every peer per-axis empty gate uses
6497    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6498    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6499    /// [`ManifestError::RepositorioEmpty`],
6500    /// [`ManifestError::DescricaoEmpty`]).
6501    ///
6502    /// Universal-axis (every kind carries `:licenca`), so wired at
6503    /// the caixa-build gate alongside the peer universal gates
6504    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6505    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6506    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6507    /// [`Self::validate_descricao`] / [`Self::validate_code_paths`]
6508    /// — before the kind-coherence gates
6509    /// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6510    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6511    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6512    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6513    /// specific slot sets.
6514    ///
6515    /// Past the empty arm the gate enforces the SPDX-expression shape
6516    /// predicate via [`crate::render::is_spdx_expression_shape`]: the
6517    /// structural alphabet floor every realistic SPDX expression in
6518    /// the wild uses — ASCII alphanumeric plus `.`, `-`, `+`, `(`,
6519    /// `)`, `:` (the `DocumentRef-…:LicenseRef-…` separator), and a
6520    /// single ASCII space (token separator). Closes the canonical
6521    /// paste-from-doc footguns the bare empty-arm gate left open:
6522    /// paste-from-doc whitespace (`"MIT "`, `" MIT"`), paste-from-
6523    /// multiline-doc CRLF (`"MIT\n"`), tab-from-aligned-doc
6524    /// (`"MIT\tOR Apache-2.0"`), non-ASCII smart-quote paste,
6525    /// underscore-instead-of-hyphen typo (`"Apache_2.0"`),
6526    /// comma-instead-of-`OR`-keyword colloquial idiom (`"MIT,
6527    /// Apache-2.0"`), slash-dual-license colloquial idiom (`"MIT/
6528    /// Apache-2.0"`), and semicolon-list-separator confusion
6529    /// (`"MIT; Apache-2.0"`). Mirrors the shape-predicate cascade
6530    /// [`Self::validate_repositorio`] / [`Self::validate_edicao`]
6531    /// establish past their own empty arms.
6532    ///
6533    /// The empty-first cascade discipline mirrors every peer per-axis
6534    /// identity gate: [`ManifestError::LicencaEmpty`] runs before
6535    /// [`ManifestError::LicencaInvalid`], so the narrower empty
6536    /// diagnostic surfaces on `Some("")` rather than the broader
6537    /// shape-predicate diagnostic — peer with how
6538    /// [`ManifestError::EdicaoEmpty`] runs before
6539    /// [`ManifestError::EdicaoInvalid`],
6540    /// [`ManifestError::RepositorioEmpty`] runs before
6541    /// [`ManifestError::RepositorioInvalid`].
6542    ///
6543    /// A future tightening on this axis can extend the alphabet
6544    /// floor into a full SPDX expression parser + license-id
6545    /// allowlist (rejecting alphabet-valid values that don't name a
6546    /// real SPDX license identifier — e.g., `"NotAReal"` is
6547    /// alphabet-valid but no `NotAReal` license-id exists). That
6548    /// parser only becomes meaningful past a real SPDX-spec
6549    /// dependency; this gate establishes the structural floor by
6550    /// refusing every non-SPDX-alphabet value at validate time.
6551    pub fn validate_licenca(&self) -> Result<(), ManifestError> {
6552        let Some(s) = self.licenca() else {
6553            return Ok(());
6554        };
6555        if s.is_empty() {
6556            return Err(ManifestError::LicencaEmpty);
6557        }
6558        crate::render::is_spdx_expression_shape(s)
6559            .map_err(|reason| ManifestError::licenca_invalid(s, reason))?;
6560        Ok(())
6561    }
6562
6563    /// Reject `:edicao` values that are the empty string. The flat
6564    /// `edicao: Option<String>` slot on [`Caixa`] is the universal
6565    /// language-edition axis every kind carries — it determines the
6566    /// tatara-lisp macro surface + compatibility flags the substrate
6567    /// applies when building a caixa, and lands verbatim in the
6568    /// `Caixa::template` author-time scaffold (the canonical
6569    /// `:edicao "2026"` line every `feira init` emits via
6570    /// [`Caixa::template`] at `caixa-core/src/manifest.rs:1193`) and
6571    /// in every renderer-side fixture (`caixa-helm/src/lib.rs:375`,
6572    /// `caixa-flux/src/lib.rs:445`, `caixa-mesh/src/lib.rs:629`,
6573    /// `caixa-core/src/render.rs:2510`) via
6574    /// `edicao: Some("2026".into())`.
6575    ///
6576    /// `None` (the canonical "omit the slot to defer to the
6577    /// substrate's default edition" shape every existing
6578    /// [`caixa-resolver`] integration test fixture carries via
6579    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
6580    /// is accepted trivially — the gate is a no-op when the author
6581    /// didn't declare a value. `Some("")` is gated by the narrower
6582    /// [`ManifestError::EdicaoEmpty`] arm, mirroring the empty-arm
6583    /// shape every peer per-axis empty gate uses
6584    /// ([`ManifestError::NomeEmpty`], [`ManifestError::VersaoEmpty`],
6585    /// [`ManifestError::EtiquetaEmpty`], [`ManifestError::AutorEmpty`],
6586    /// [`ManifestError::RepositorioEmpty`],
6587    /// [`ManifestError::DescricaoEmpty`], [`ManifestError::LicencaEmpty`]).
6588    ///
6589    /// Universal-axis (every kind carries `:edicao`), so wired at
6590    /// the caixa-build gate alongside the peer universal gates
6591    /// [`Self::validate_nome`] / [`Self::validate_versao`] /
6592    /// [`Self::validate_deps`] / [`Self::validate_etiquetas`] /
6593    /// [`Self::validate_autores`] / [`Self::validate_repositorio`] /
6594    /// [`Self::validate_descricao`] / [`Self::validate_licenca`] /
6595    /// [`Self::validate_code_paths`] — before the kind-coherence
6596    /// gates ([`crate::LayoutError::MeshSlotsOnNonAplicacao`] /
6597    /// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] /
6598    /// [`crate::LayoutError::ServicoSlotsOnNonServico`] /
6599    /// [`crate::LayoutError::ForeignCodeSlot`]) which fence kind-
6600    /// specific slot sets.
6601    ///
6602    /// Past the empty arm the gate enforces the canonical year-shape
6603    /// predicate: every documented tatara-lisp edition is a 4-digit
6604    /// ASCII decimal year (`"2026"` is the only edition currently
6605    /// minted; future-introduced siblings will follow the same
6606    /// shape, peer with Cargo's `[package] edition` grammar which
6607    /// every value Cargo has ever accepted matches — `"2015"`,
6608    /// `"2018"`, `"2021"`, `"2024"`). Any value that's not exactly
6609    /// 4 ASCII decimal bytes is rejected with the narrower
6610    /// [`ManifestError::EdicaoInvalid`] arm, mirroring the
6611    /// shape-predicate cascade [`Self::validate_repositorio`]
6612    /// establishes past its own empty arm
6613    /// ([`ManifestError::RepositorioEmpty`] →
6614    /// [`ManifestError::RepositorioInvalid`]). Closes the canonical
6615    /// paste-from-doc footguns the bare empty-arm gate left open:
6616    ///
6617    ///   - leading / trailing whitespace from a paste-from-doc
6618    ///     (`"2026 "`, `" 2026"`)
6619    ///   - control characters / CRLF from a paste-from-multiline-doc
6620    ///     (`"2026\n"`)
6621    ///   - non-ASCII look-alikes from a fullwidth keyboard
6622    ///     (`"2026"`) which would silently land as a non-ASCII
6623    ///     string in the rendered caixa.lisp
6624    ///   - free-form non-year values (`"x"`, `"latest"`,
6625    ///     `"nightly"`) that have no operational meaning on the
6626    ///     substrate's build-time edition selector
6627    ///   - leading non-digit prefixes (`"v2026"`, `"e2026"`,
6628    ///     `"r2026"`) — common version-tag idioms that don't apply
6629    ///     to the year-shaped edition axis
6630    ///   - decimal-shaped values (`"2026.1"`, `"2026.0"`) — every
6631    ///     edition is a year, not a fractional version
6632    ///   - wrong-length numeric values (`"26"`, `"202"`, `"20260"`,
6633    ///     `"00026"`) that don't name a year
6634    ///
6635    /// `None` (the canonical "omit the slot to defer to the
6636    /// substrate's default edition" shape every existing
6637    /// [`caixa-resolver`] integration test fixture carries via
6638    /// `edicao: None` — see `caixa-resolver/tests/git_integration.rs`)
6639    /// is accepted trivially — the gate is a no-op when the author
6640    /// didn't declare a value. The empty-first cascade discipline
6641    /// mirrors every peer per-axis identity gate:
6642    /// [`ManifestError::EdicaoEmpty`] runs before
6643    /// [`ManifestError::EdicaoInvalid`], so the narrower empty
6644    /// diagnostic surfaces on `Some("")` rather than the broader
6645    /// shape-predicate diagnostic — peer with how
6646    /// [`ManifestError::NomeEmpty`] runs before
6647    /// [`ManifestError::NomeInvalid`],
6648    /// [`ManifestError::VersaoEmpty`] runs before
6649    /// [`ManifestError::VersaoInvalid`],
6650    /// [`ManifestError::RepositorioEmpty`] runs before
6651    /// [`ManifestError::RepositorioInvalid`].
6652    ///
6653    /// A future tightening on this axis can extend the shape
6654    /// predicate into a known-edition allowlist (rejecting
6655    /// year-shaped values that don't name a tatara-lisp edition
6656    /// the substrate actually understands — e.g., `"1999"` is
6657    /// year-shaped but no `1999` edition exists). That allowlist
6658    /// only becomes meaningful past the introduction of a sibling
6659    /// edition to `"2026"`; this gate establishes the structural
6660    /// floor by refusing every non-year-shaped value at validate
6661    /// time.
6662    pub fn validate_edicao(&self) -> Result<(), ManifestError> {
6663        let Some(s) = self.edicao() else {
6664            return Ok(());
6665        };
6666        if s.is_empty() {
6667            return Err(ManifestError::EdicaoEmpty);
6668        }
6669        if s.len() != 4 || !s.bytes().all(|b| b.is_ascii_digit()) {
6670            return Err(ManifestError::edicao_invalid(
6671                s,
6672                "must be a 4-digit ASCII decimal year (canonical \"2026\")",
6673            ));
6674        }
6675        Ok(())
6676    }
6677
6678    /// Compose the supervisor-related flat slots into a single
6679    /// [`SupervisorSpec`] for validation. Returns `None` when the
6680    /// caixa isn't a `:kind Supervisor`.
6681    ///
6682    /// The flat representation in [`Caixa`] keeps tatara-lisp authoring
6683    /// simple (one form, no nested `:supervisor (…)` block); this view
6684    /// is the "typed shape" the operator + supervisor reconciler
6685    /// consume.
6686    #[must_use]
6687    pub fn supervisor_view(&self) -> Option<SupervisorSpec> {
6688        if !self.kind().is_supervisor() {
6689            return None;
6690        }
6691        // Fold through the shared `supervisor::duration_codec::parse`
6692        // — the same parser the serde-routed `with = "duration_codec"`
6693        // on `SupervisorSpec::restart_window`, the `:politicas
6694        // :timeout` codec, and the `:politicas :circuit-breaker
6695        // :window` codec all consume. The prior inline f64-shaped
6696        // duplicate (`parse_window_inline`) admitted every magnitude
6697        // the integer-magnitude gate (1c55a2a) rejects on the three
6698        // serde-routed siblings — `"1.5s"`, `"1.0s"`, `"0.5m"`,
6699        // `"+30s"`, `"-30s"` — and silently dropped malformed input as
6700        // `None` (i.e. "no reset"), divergent from the shared codec's
6701        // integer-magnitude discipline by construction. The fold
6702        // closes the divergence: every value the typed
6703        // `SupervisorSpec` carries past `supervisor_view` is in the
6704        // shared codec's accepted set. The `.ok()` here preserves the
6705        // existing soft-swallow shape on this view-construction path;
6706        // the new [`Caixa::validate_restart_window`] (sibling of
6707        // [`Self::validate_nome`] / [`Self::validate_versao`]) names
6708        // the offending raw string at build time so authoring tools
6709        // (`feira lint`, the future layout-side wire-up) surface a
6710        // self-locating diagnostic instead of a silently dropped
6711        // window.
6712        let restart_window = self
6713            .restart_window()
6714            .and_then(|s| crate::supervisor::duration_codec::parse(s).ok());
6715        Some(SupervisorSpec {
6716            // Route the author-omitted `:estrategia` arm through the
6717            // substrate-canonical
6718            // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
6719            // `pub const` rather than the transitively-derived
6720            // [`RestartStrategy::default`] route the prior
6721            // `.unwrap_or_default()` fold reached for — one source of
6722            // truth for the Erlang/OTP `one_for_one` half of Learn You
6723            // Some Erlang's `{one_for_one, intensity, 5, 60}` worker-
6724            // supervisor canonical default that also backs the
6725            // [`crate::supervisor::Default for RestartStrategy`] impl
6726            // and the [`crate::supervisor::Default for SupervisorSpec`]
6727            // impl's struct-literal `estrategia` field, all now routed
6728            // through the same lifted constant. Prior to the lift the
6729            // composition site carried `.unwrap_or_default()` with no
6730            // compile-time link back to the shared OTP-canonical
6731            // default that the peer paired
6732            // `.unwrap_or(SUPERVISOR_MAX_RESTARTS_DEFAULT)` (b698ec0)
6733            // arm on the sibling `:max-restarts` axis routes through —
6734            // so a future rebrand of the OTP-canonical strategy default
6735            // (a widening to `rest_for_one` once the substrate
6736            // discovers startup-order-coupled child cohorts as the more
6737            // common shape, a per-cluster overlay the operator pins
6738            // through the MESH-COMPOSITION §III.2 supervision-canary
6739            // `:estrategia-overrides` roadmap slot) would have had to
6740            // migrate the paired `MaxIntensity` + `Period` halves
6741            // through the lifted constants and the `one_for_one` half
6742            // through a `RestartStrategy::default()` route in lockstep
6743            // or the three halves of the same OTP-canonical default
6744            // would silently drift out of pairing. Byte-parity against
6745            // the lifted constant closes the split. Pinned by
6746            // [`supervisor_view_estrategia_fallback_routes_through_lifted_default`]
6747            // in the tests module.
6748            estrategia: self
6749                .estrategia()
6750                .unwrap_or(crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT),
6751            // Route the author-omitted `:max-restarts` arm through the
6752            // substrate-canonical [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`]
6753            // typed `pub const` rather than the raw `5` literal — one
6754            // source of truth for the Erlang/OTP-canonical
6755            // `{intensity, 5, 60}` `MaxIntensity` default that also
6756            // backs the serde-side wire-format author-omitted arm on
6757            // [`crate::supervisor::SupervisorSpec::max_restarts`] via
6758            // `#[serde(default = "default_max_restarts")]` and the
6759            // [`Default for SupervisorSpec`] impl's struct-literal
6760            // default field. Prior to the lift the composition site
6761            // carried a raw `5` with no compile-time link back to the
6762            // serde-side default, so a future rebrand of the OTP-
6763            // canonical default (a tightening to Elixir's `3`, a
6764            // widening to a per-cluster overlay the operator pins
6765            // through the MESH-COMPOSITION §III.2 supervision-canary
6766            // `:supervisor :max-restarts-overrides` roadmap slot)
6767            // would have had to be threaded through both open-coded
6768            // copies in lockstep or the wire-format author-omitted arm
6769            // and this view-construction author-omitted arm would
6770            // silently disagree on which restart-budget an omitted
6771            // `:max-restarts` resolves to. Pinned by
6772            // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
6773            // in the tests module.
6774            max_restarts: self
6775                .max_restarts()
6776                .unwrap_or(crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT),
6777            restart_window,
6778            children: self.children().to_vec(),
6779        })
6780    }
6781
6782    /// A minimal starter manifest emitted by `feira init`.
6783    #[must_use]
6784    pub fn template(nome: &str) -> String {
6785        format!(
6786            "(defcaixa\n  \
6787               :nome        {nome:?}\n  \
6788               :versao      \"0.1.0\"\n  \
6789               :kind        Biblioteca\n  \
6790               :edicao      \"2026\"\n  \
6791               :descricao   \"FIXME — describe this caixa\"\n  \
6792               :autores     ()\n  \
6793               :etiquetas   ()\n  \
6794               :deps        ()\n  \
6795               :deps-dev    ()\n  \
6796               :bibliotecas (\"lib/{nome}.lisp\"))\n"
6797        )
6798    }
6799
6800    /// Serialize to a canonical `caixa.lisp` source — suitable for writing
6801    /// back after mutation (e.g. `feira add`).
6802    ///
6803    /// Goes through serde JSON → canonical Sexp → per-field pretty print.
6804    /// The derive-macro `compile_from_sexp` path is the inverse, so any
6805    /// `Caixa` round-trips through `to_lisp` + `from_lisp`.
6806    #[must_use]
6807    pub fn to_lisp(&self) -> String {
6808        let json = serde_json::to_value(self).expect("Caixa serialize");
6809        let sexp = tatara_lisp::domain::json_to_sexp(&json);
6810        let tatara_lisp::Sexp::List(items) = sexp else {
6811            return format!("(defcaixa {sexp})\n");
6812        };
6813        let mut out = String::from("(defcaixa");
6814        let mut i = 0;
6815        while i + 1 < items.len() {
6816            out.push_str("\n  ");
6817            out.push_str(&items[i].to_string());
6818            out.push(' ');
6819            out.push_str(&items[i + 1].to_string());
6820            i += 2;
6821        }
6822        out.push_str(")\n");
6823        out
6824    }
6825}
6826
6827/// Errors raised by top-level [`Caixa`] validators that don't fit
6828/// the per-axis [`DepError`] / [`crate::AplicacaoError`] /
6829/// [`crate::SupervisorError`] / [`crate::LayoutError`] families —
6830/// the Caixa's own identity axes (`:nome`, `:versao`) that flow
6831/// through every substrate-side artifact's `metadata.name` /
6832/// version derivation.
6833///
6834/// A future top-level sum (the M4 `CaixaError` the [`DepError`]
6835/// doc-comment anticipates) can hold one of each per-axis error
6836/// family without reshaping individual diagnostics; this enum is
6837/// the first such per-Caixa-identity family.
6838#[derive(Debug, Error, PartialEq, Eq)]
6839pub enum ManifestError {
6840    #[error(
6841        ":nome is empty (every caixa must name itself; the value flows \
6842         into every K8s artifact's `metadata.name` derivation and into \
6843         the default `lib/<nome>.lisp` / `exe/<nome>` layout paths)"
6844    )]
6845    NomeEmpty,
6846    #[error(
6847        ":nome {nome:?} is not a valid DNS-1123 label: {reason} (the K8s \
6848         apiserver enforces this rule on every `metadata.name` the \
6849         caixa's substrate-side renderers derive from `:nome` — the \
6850         `lareira-<nome>` Helm chart name, the programs.yaml entry \
6851         name, the `LABEL_APLICACAO` label value, the `<aplicacao>-<de>-to-<para>` \
6852         CiliumNetworkPolicy name, the `<aplicacao>-<para>` HTTPRoute \
6853         name; use a lowercase alphanumeric + hyphen identifier like \
6854         `\"checkout\"` or `\"cart-v2\"`)"
6855    )]
6856    NomeInvalid { nome: String, reason: String },
6857    #[error(
6858        ":nome {nome:?} overflows the joint-length budget on the canonical \
6859         `lareira-<nome>` chart-name shape: {reason} (every per-Servico / \
6860         per-Aplicacao renderer the substrate carries — `caixa-helm`'s \
6861         `Chart.yaml::name`, `caixa-flux`'s `cluster_bundle` HelmRelease \
6862         `chart:` slot, `caixa-tatara`'s `release_name` + \
6863         `oci://<registry>/lareira-<nome>` chart ref — derives the same \
6864         joint name through the canonical `lareira_chart_name` helper, and \
6865         Helm's `Chart.yaml::name` admission rule + the K8s apiserver's \
6866         DNS-1123 label cap on every chart-name-derived `metadata.name` \
6867         reject any joint name exceeding 63 bytes; the narrower \
6868         `:nome` shape (`NomeInvalid`) gates the bare-`:nome` budget, this \
6869         arm gates the chart-name budget downstream renderers inherit)"
6870    )]
6871    NomeChartNameBudgetExceeded { nome: String, reason: String },
6872    #[error(
6873        ":versao is empty (every caixa must pin its own version; the value flows \
6874         into the `lareira-<nome>` Helm chart's `Chart.yaml` version + appVersion, \
6875         the `feira publish` `v<versao>` git tag, the OCI image's `:v<versao>` / \
6876         `:latest` tags, the lacre closure's `concrete_versao`, and the \
6877         `:upgrade-from :from` peers — use a SemVer-2 literal like `\"0.1.0\"`)"
6878    )]
6879    VersaoEmpty,
6880    #[error(
6881        ":versao {versao:?} is not a valid SemVer-2 version: {reason} (the substrate \
6882         consumes this string as `semver::Version` — three-part `MAJOR.MINOR.PATCH` \
6883         with optional `-prerelease` and `+build` — across every artifact derived \
6884         from `:versao`: the `lareira-<nome>` Helm chart's `Chart.yaml` version + \
6885         appVersion (Helm SemVer-2-strict), the `feira publish` `v<versao>` git tag, \
6886         the OCI image's `:v<versao>` tag, the lacre closure's `concrete_versao`, \
6887         and the `:upgrade-from :from` peers that match against this exact shape; \
6888         use a literal like `\"0.1.0\"`, `\"0.2.0-rc.1\"`, or `\"1.0.0+build.42\"` — \
6889         not a git-tag-shape like `\"v0.1.0\"`, a docker-tag-shape like `\"latest\"`, \
6890         a requirement-shape like `\"^0.1\"`, or a four-part `\"0.1.0.0\"`)"
6891    )]
6892    VersaoInvalid { versao: String, reason: String },
6893    #[error(
6894        ":restart-window {restart_window:?} is not a valid duration: {reason} (the \
6895         substrate consumes this string through the shared \
6896         `supervisor::duration_codec` — the same parser routed via `with = \
6897         \"duration_codec\"` onto the typed `SupervisorSpec::restart_window`, \
6898         `:politicas :timeout`, and `:politicas :circuit-breaker :window` slots; \
6899         the canonical authoring form is `<integer><unit>` where the unit is one \
6900         of `ms` / `s` / `m` / `h` and the magnitude has no decimal point and no \
6901         leading `+` / `-` sign — e.g. `\"60s\"`, `\"5m\"`, `\"1h\"`, `\"500ms\"`. \
6902         Without this gate a malformed `:restart-window` silently produced a \
6903         supervisor with `restart_window: None` (\"never reset\"), turning OTP's \
6904         `MaxIntensity / Period` invariant into a never-reset supervisor far from \
6905         the source `caixa.lisp`; the gate moves the diagnostic to the manifest \
6906         layer with the offending value named verbatim. Omit the slot entirely to \
6907         express \"no reset\"; carry a positive integer duration to express the \
6908         sliding window)"
6909    )]
6910    RestartWindowMalformed {
6911        restart_window: String,
6912        reason: String,
6913    },
6914    #[error(
6915        "{slot} entry is an empty path string — every {slot} entry must name \
6916         a file relative to the caixa root; omit the entry to omit the file \
6917         (the layout checker's `root.join(\"\")` resolves to the caixa root \
6918         itself, so an empty entry silently aliases the project root as a \
6919         declared {slot} file, then fails downstream at parse / existence \
6920         time with a diagnostic that names the root rather than the offending \
6921         entry)"
6922    )]
6923    CodePathEmpty { slot: &'static str },
6924    #[error(
6925        "{slot} entry {} is an absolute path — entries must be relative to \
6926         the caixa root, since `Path::join` replaces the base with an absolute \
6927         right-hand side and `root.join(\"/abs/...\")` resolves to \"/abs/...\" \
6928         outside the caixa root sandbox; rewrite the entry as a relative path \
6929         under the caixa root (e.g. `\"lib/<name>.lisp\"`, `\"exe/<name>\"`, \
6930         `\"servicos/<name>.computeunit.yaml\"`)",
6931        path.display()
6932    )]
6933    CodePathAbsolute { slot: &'static str, path: PathBuf },
6934    #[error(
6935        "{slot} entry {} contains a `..` component — entries must not traverse \
6936         above the caixa root (the layout's `starts_with(<dir>)` fence on \
6937         `:exe` / `:servicos` is component-aware, not canonical-path-aware, \
6938         so a mid-path `..` silently traverses the sandbox; `:bibliotecas` \
6939         has no such fence, so a leading `..` escapes unconditionally if the \
6940         resolved target happens to exist)",
6941        path.display()
6942    )]
6943    CodePathParentEscape { slot: &'static str, path: PathBuf },
6944    #[error(
6945        "{slot} entry {} does not terminate in the `.lisp` extension — every \
6946         `:bibliotecas` entry is a tatara-lisp source file the `feira build` \
6947         loop reads through `tatara_lisp::read` at parse time, so any other \
6948         extension (`.rs`, `.txt`, `.lisp.bak`) or no-extension shape is \
6949         structurally a parser error far from the source caixa.lisp, with \
6950         no field naming the offending `:bibliotecas` entry. Pin a relative \
6951         path under the caixa root whose terminating extension is \
6952         lowercase-`.lisp` (e.g. `\"lib/<name>.lisp\"`, \
6953         `\"lib/handlers.lisp\"`) — the same file-type contract the peer \
6954         `:behavior :on-*` (c97815a) and `:upgrade-from :state-change :script` \
6955         (33cc830) axes already carry through the same lifted \
6956         `is_lisp_extension` predicate",
6957        path.display()
6958    )]
6959    CodePathNonLispExtension { slot: &'static str, path: PathBuf },
6960    #[error(
6961        "{slot} entry {} does not terminate in the `.computeunit.yaml` \
6962         compound suffix — every `:servicos` entry is a typed `ComputeUnit` \
6963         CR YAML file the peer caixa-helm / caixa-flux renderers consume \
6964         through `serde_yaml::from_str` at chart / FluxCD bundle render \
6965         time, so any other extension (`.yaml`, `.yml`, `.json`, the \
6966         off-by-one-segment `.computeunit-yaml`, the editor-backup \
6967         `.computeunit.yaml.bak`) or no-extension shape is structurally a \
6968         YAML-parser error / `ComputeUnit` schema-mismatch far from the \
6969         source caixa.lisp, with no field naming the offending `:servicos` \
6970         entry. Pin a relative path under the caixa root whose terminating \
6971         compound suffix is lowercase-`.computeunit.yaml` (e.g. \
6972         `\"servicos/<name>.computeunit.yaml\"`, \
6973         `\"servicos/hello-rio.computeunit.yaml\"`) — the same file-type \
6974         contract the sibling `:bibliotecas` axis (64772a9) already carries \
6975         on the tatara-lisp-source axis through the peer lifted \
6976         `is_lisp_extension` predicate, here on the compound-suffix axis \
6977         `Path::extension` can't express on its own through the lifted \
6978         `is_computeunit_yaml_extension` predicate",
6979        path.display()
6980    )]
6981    CodePathNonComputeUnitYamlExtension { slot: &'static str, path: PathBuf },
6982    #[error(
6983        "{slot} entry {} appears more than once (the code-path list is \
6984         a set, not a multiset; every peer Vec-shaped author-supplied \
6985         list past validate is set-not-multiset — `:membros :caixa`, \
6986         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
6987         `:children :caixa`, `:deps` / `:deps-dev` `:nome`, \
6988         `:upgrade-from :from`, `:etiquetas`, `:autores` — and the three \
6989         code-path lists are the last Vec-shaped author-supplied slots on \
6990         the typed Caixa surface still admitting a duplicate entry. \
6991         `:bibliotecas` duplicates re-parse the same file at \
6992         `feira build` time and silently mask the author's intent to \
6993         declare a *second* biblioteca; `:exe` duplicates collide on the \
6994         flake `packages.<name>` derivation key at the future \
6995         `caixa-flake` materializer; `:servicos` duplicates surface as the \
6996         narrower [`caixa-helm`] / [`caixa-flux`] `UnsupportedServicoCount` \
6997         rejection far from the source `caixa.lisp`. Drop the duplicate \
6998         or rename it to the actual second file intended)",
6999        path.display()
7000    )]
7001    CodePathDuplicate { slot: &'static str, path: PathBuf },
7002    #[error(
7003        ":etiquetas entry is empty (every tag must carry a non-empty \
7004         registry-search identifier; the empty entry has no operational \
7005         meaning — it indexes nothing in the future caixa-registry search \
7006         axis and clutters the rendered Helm `Chart.yaml` `keywords:` array \
7007         with a no-op tag; omit the entry to express \"no tag on this \
7008         position\")"
7009    )]
7010    EtiquetaEmpty,
7011    #[error(
7012        ":etiquetas entry {etiqueta:?} appears more than once (the \
7013         registry-search tag set is a set, not a multiset; duplicate \
7014         entries are silently dedup'd by caixa-helm's `BTreeSet` collect \
7015         at chart render — a \"second wins / one silently disappears\" \
7016         shape divergent from every peer typed-graph set gate \
7017         (`:membros :caixa`, `:placement :clusters`, `:entrada :paths`, \
7018         `:contratos`, `:deps :nome`, `:upgrade-from :from`); drop the \
7019         duplicate or rename it to the actual tag intended)"
7020    )]
7021    EtiquetaDuplicate { etiqueta: String },
7022    #[error(
7023        ":etiquetas entry {etiqueta:?} is not a valid chart-keyword shape: \
7024         {reason} (the substrate consumes this string through the shared \
7025         `crate::render::is_chart_keyword_shape` predicate — the same \
7026         Cargo crates.io `[package] keywords` grammar entry shape: 1..=20 \
7027         bytes, starts with an ASCII letter, ASCII alphanumeric / `_` / `-` \
7028         continuation. The canonical authoring shapes are short kebab-case \
7029         identifiers like `\"mesh\"`, `\"wasm\"`, `\"tatara-lisp\"`, \
7030         `\"hello-world\"`, `\"caixa-servico\"`, `\"infrastructure\"`. \
7031         Without this gate a malformed `:etiquetas` entry (paste-from-doc \
7032         leading / trailing whitespace `\" mesh\"` / `\"mesh \"`; \
7033         paste-from-multiline-doc newline `\"mesh\\nhttp\"`; \
7034         paste-from-Windows-CRLF-doc CR; CSV-list-separator confusion \
7035         `\"mesh,http,grpc\"` — the author meant to author three separate \
7036         list entries; path-separator confusion `\"caixa/servico\"`; \
7037         namespace-suffix `\"http.1\"`; leading-digit `\"1foo\"`; \
7038         kebab-leak `\"-foo\"`; snake-leak `\"_foo\"`; non-ASCII \
7039         `\"café\"` — every legitimate search tag is strict ASCII; \
7040         paste-from-binary-blob NUL / BEL / ESC / DEL byte) silently \
7041         passed `from_lisp` + `validate_etiquetas` + \
7042         `StandardLayout::verify` and landed in the rendered \
7043         `lareira-<nome>` Helm chart's `Chart.yaml keywords:` array as a \
7044         malformed search tag — Artifact Hub's keyword index + the future \
7045         caixa-registry's keyword index would either silently drop the \
7046         tag or fail to index it far from the source caixa.lisp; the gate \
7047         moves the diagnostic to the manifest layer with the offending \
7048         value named verbatim)"
7049    )]
7050    EtiquetaInvalid { etiqueta: String, reason: String },
7051    #[error(
7052        ":autores entry is empty (every maintainer must carry a non-empty \
7053         identifier; the empty entry has no operational meaning — it \
7054         identifies no one in the substrate's authorship index and renders \
7055         as `maintainers: [{{name: \"\", email: null}}]` in the Helm chart's \
7056         `Chart.yaml`, a no-op maintainer the substrate cannot route to; \
7057         omit the entry to express \"no maintainer on this position\")"
7058    )]
7059    AutorEmpty,
7060    #[error(
7061        ":autores entry {autor:?} appears more than once (the maintainer \
7062         set is a set, not a multiset; unlike `:etiquetas`, caixa-helm's \
7063         `maintainers:` rendering does *no* dedup — duplicate entries \
7064         stack verbatim in `Chart.yaml` as two identical \
7065         `Maintainer {{ name, email: None }}` records, divergent from every \
7066         peer typed-graph set gate (`:etiquetas`, `:membros :caixa`, \
7067         `:placement :clusters`, `:entrada :paths`, `:contratos`, \
7068         `:deps :nome`, `:upgrade-from :from`); drop the duplicate or \
7069         rename it to the actual author intended)"
7070    )]
7071    AutorDuplicate { autor: String },
7072    #[error(
7073        ":autores entry {autor:?} is not a valid chart-maintainer-name shape: \
7074         {reason} (the substrate consumes this string through the shared \
7075         `crate::render::is_chart_maintainer_name_shape` predicate — the same \
7076         single-line-UTF-8 floor every realistic chart maintainer name carries: \
7077         1..=128 bytes, no leading or trailing whitespace, no ASCII control \
7078         characters anywhere, Unicode bytes accepted. The canonical authoring \
7079         shapes are short single-line identifiers like `\"pleme-io\"`, \
7080         `\"Pleme Contributors\"`, `\"alice <alice@example.com>\"`, \
7081         `\"François Dupont\"`. Without this gate a malformed `:autores` entry \
7082         (paste-from-aligned-doc leading whitespace `\" pleme-io\"` / trailing \
7083         whitespace `\"pleme-io \"`; paste-from-multiline-doc newline \
7084         `\"alice\\nbob\"` — the author pasted a multi-line block of author \
7085         records into one entry instead of splitting into one entry per author; \
7086         paste-from-Windows-CRLF-doc carriage return `\"alice\\rbob\"`; \
7087         tab-from-aligned-doc `\"Pleme\\tContributors\"`; paste-from-binary-blob \
7088         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
7089         `validate_autores` + `StandardLayout::verify` and landed in the \
7090         rendered `lareira-<nome>` Helm chart's `Chart.yaml maintainers:` array \
7091         as a YAML-illegal multi-line scalar or a silently-trimmed whitespace \
7092         round-trip — every chart-aware UI (`helm list`, `helm search`, \
7093         Artifact Hub maintainer index) would render the maintainer name in a \
7094         single-line column far from the source caixa.lisp; the gate moves the \
7095         diagnostic to the manifest layer with the offending value named \
7096         verbatim)"
7097    )]
7098    AutorInvalid { autor: String, reason: String },
7099    #[error(
7100        ":repositorio is the empty string (every published caixa names its \
7101         git source via a non-empty `:repositorio` locator — the value \
7102         flows verbatim into the rendered `lareira-<nome>` Helm chart's \
7103         `Chart.yaml` `home:` field via `caixa-helm` and into the FluxCD \
7104         `GitRepository.spec.url` via `caixa-flux`'s \
7105         `ClusterBundleOpts::for_caixa`; both consumers' \
7106         `Option::unwrap_or_else` fallbacks only fire when the slot is \
7107         `None`, so an empty `Some(\"\")` silently lands as `home: \"\"` / \
7108         `url: \"\"` in the rendered artifacts and breaks at `helm \
7109         template` / FluxCD source-controller reconcile time far from the \
7110         source caixa.lisp; omit the slot entirely to defer to the \
7111         renderer's `https://github.com/pleme-io/<nome>` / \
7112         `caixa.nome`-derived fallback, or carry a canonical authoring \
7113         shape like `\"github:org/repo\"`, `\"https://host/path\"`, \
7114         `\"ssh://[user@]host/path\"`, `\"git@host:path\"`, or \
7115         `\"file:///path\"`)"
7116    )]
7117    RepositorioEmpty,
7118    #[error(
7119        ":repositorio {repositorio:?} is not a valid git repo URL: {reason} \
7120         (the substrate consumes this string through the shared \
7121         `crate::render::is_git_repo_url` predicate — the same parser the \
7122         peer `:deps :fonte (:tipo git :repo …)` axis routes its `:repo` \
7123         value through via `DepSource::validate`; the canonical authoring \
7124         shapes are `\"github:org/repo\"` shorthand, `\"https://host/path\"` \
7125         / `\"ssh://[user@]host/path\"` / `\"git://host/path\"` / \
7126         `\"file:///path\"` URL schemes, or the `\"git@host:path\"` \
7127         scp-style SSH form. Without this gate a malformed `:repositorio` \
7128         (whitespace from a paste-from-doc; control characters / CRLF \
7129         from a paste-from-multiline-doc; a leading `-` from a \
7130         CLI-argument-injection footgun; a missing `:` separator from a \
7131         bare `org/repo` shape git treats as a relative filesystem path) \
7132         silently landed in the rendered `Chart.yaml home:` and the \
7133         FluxCD `GitRepository.spec.url` and broke at `git clone` / \
7134         FluxCD reconcile time far from the source caixa.lisp; the gate \
7135         moves the diagnostic to the manifest layer with the offending \
7136         value named verbatim)"
7137    )]
7138    RepositorioInvalid { repositorio: String, reason: String },
7139    #[error(
7140        ":descricao is the empty string (every published caixa names \
7141         its purpose via a non-empty `:descricao` summary — the value \
7142         flows verbatim into the rendered `lareira-<nome>` Helm \
7143         chart's `Chart.yaml` `description:` field via `caixa-helm`'s \
7144         `build_chart_yaml` and into the chart `README.md` header via \
7145         `build_readme`; both consumers' `Option::unwrap_or_else` \
7146         `caixa.nome`-derived fallbacks only fire when the slot is \
7147         `None`, so an empty `Some(\"\")` silently lands as \
7148         `description: \"\"` / a blank `README.md` header in the \
7149         rendered artifacts and breaks at `helm lint` time \
7150         (`WARNING [chart.metadata.description]: description is \
7151         required` on `apiVersion: v2` charts) far from the source \
7152         caixa.lisp; omit the slot entirely to defer to the \
7153         renderer's `\"Generated chart for caixa Servico <nome>\"` / \
7154         `\"caixa Servico <nome>\"` fallbacks, or carry a non-empty \
7155         summary like `\"Canonical Rust→wasm32-wasip2 caixa \
7156         Servico.\"`)"
7157    )]
7158    DescricaoEmpty,
7159    #[error(
7160        ":descricao {descricao:?} is not a valid chart-description shape: \
7161         {reason} (the substrate consumes this string through the shared \
7162         `crate::render::is_chart_description_shape` predicate — the same \
7163         single-line-UTF-8 floor every realistic chart description carries: \
7164         1..=512 bytes, no leading or trailing whitespace, no ASCII control \
7165         characters anywhere, Unicode prose bytes accepted. The canonical \
7166         authoring shapes are short single-line summaries like `\"Canonical \
7167         Rust→wasm32-wasip2 caixa Servico.\"`, `\"Checkout flow.\"`, \
7168         `\"AWS provider caixa for tatara-lisp\"`. Without this gate a \
7169         malformed `:descricao` (paste-from-aligned-doc leading whitespace \
7170         `\" Checkout flow.\"` / trailing whitespace `\"Checkout flow. \"`; \
7171         paste-from-multiline-doc newline `\"Checkout\\nflow.\"`; \
7172         paste-from-Windows-CRLF-doc carriage return `\"Checkout\\rflow.\"`; \
7173         tab-from-aligned-doc `\"Checkout\\tflow.\"`; paste-from-binary-blob \
7174         NUL / BEL / ESC / DEL byte) silently passed `from_lisp` + \
7175         `validate_descricao` + `StandardLayout::verify` and landed in the \
7176         rendered `lareira-<nome>` Helm chart's `Chart.yaml description:` \
7177         field + `README.md` header paragraph as a YAML-illegal multi-line \
7178         scalar or a silently-trimmed whitespace round-trip — every \
7179         chart-aware UI (`helm list`, `helm search`, Artifact Hub) would \
7180         render the description in a single-line column far from the source \
7181         caixa.lisp; the gate moves the diagnostic to the manifest layer \
7182         with the offending value named verbatim)"
7183    )]
7184    DescricaoInvalid { descricao: String, reason: String },
7185    #[error(
7186        ":licenca is the empty string (every published caixa names \
7187         its license via a non-empty `:licenca` SPDX expression — the \
7188         value flows verbatim into the rendered `lareira-<nome>` Helm \
7189         chart's `README.md` `## License` section via `caixa-helm`'s \
7190         `build_readme` at `caixa-helm/src/lib.rs:361`; the consumer's \
7191         `Option::unwrap_or_else(|| \"MIT\".into())` `MIT` fallback \
7192         only fires when the slot is `None`, so an empty `Some(\"\")` \
7193         silently lands as a bare trailing period in the rendered \
7194         chart `README.md` `License` section far from the source \
7195         caixa.lisp; omit the slot entirely to defer to the \
7196         renderer's `MIT` fallback, or carry a canonical SPDX \
7197         expression like `\"MIT\"`, `\"Apache-2.0\"`, \
7198         `\"Apache-2.0 OR MIT\"`)"
7199    )]
7200    LicencaEmpty,
7201    #[error(
7202        ":licenca {licenca:?} is not a valid SPDX expression shape: {reason} \
7203         (the substrate consumes this string through the shared \
7204         `crate::render::is_spdx_expression_shape` predicate — the same \
7205         alphabet-floor parser every peer per-axis value-shape gate routes \
7206         its value through; the canonical authoring shapes are single \
7207         license identifiers like `\"MIT\"`, `\"Apache-2.0\"`, `\"BSD-3-Clause\"`, \
7208         compound expressions like `\"Apache-2.0 OR MIT\"`, \
7209         `\"MIT AND BSD-3-Clause\"`, `\"(MIT OR Apache-2.0) AND ISC\"`, \
7210         license-with-exception forms like `\"Apache-2.0 WITH LLVM-exception\"`, \
7211         `+`-suffix variants like `\"GPL-2.0+\"`, and user-defined references \
7212         like `\"LicenseRef-MyLicense\"` / \
7213         `\"DocumentRef-doc:LicenseRef-MyLicense\"`. Without this gate a \
7214         malformed `:licenca` (paste-from-doc whitespace `\"MIT \"` / \
7215         `\" MIT\"`; paste-from-multiline-doc CRLF `\"MIT\\n\"`; \
7216         tab-from-aligned-doc `\"MIT\\tOR Apache-2.0\"`; non-ASCII byte from \
7217         a smart-quote paste; underscore-instead-of-hyphen typo \
7218         `\"Apache_2.0\"`; comma-instead-of-`OR`-keyword colloquial idiom \
7219         `\"MIT, Apache-2.0\"`; slash-dual-license colloquial idiom \
7220         `\"MIT/Apache-2.0\"`; semicolon-list-separator confusion \
7221         `\"MIT; Apache-2.0\"`) silently landed in the rendered chart \
7222         `README.md` `## License` section + a future SPDX-aware \
7223         `Chart.yaml license:` emitter would refuse the value at \
7224         `helm lint` time far from the source caixa.lisp; the gate moves \
7225         the diagnostic to the manifest layer with the offending value \
7226         named verbatim)"
7227    )]
7228    LicencaInvalid { licenca: String, reason: String },
7229    #[error(
7230        ":edicao is the empty string (every published caixa names \
7231         its language edition via a non-empty `:edicao` value — the \
7232         edition determines the tatara-lisp macro surface + \
7233         compatibility flags the substrate applies when building \
7234         the caixa; the canonical `Caixa::template` scaffold every \
7235         `feira init` emits carries `:edicao \"2026\"` verbatim and \
7236         every renderer-side fixture (`caixa-helm`, `caixa-flux`, \
7237         `caixa-mesh`) carries `edicao: Some(\"2026\".into())` by \
7238         construction, so an empty `Some(\"\")` silently lands as a \
7239         bare `(:edicao \"\")` line in the rendered `caixa.lisp` and \
7240         a future renderer-side consumer that folds it through \
7241         `Option::unwrap_or_else` will skip the fallback and pass the \
7242         empty edition through to the substrate's build-time edition \
7243         selector far from the source caixa.lisp; omit the slot \
7244         entirely to defer to the substrate's default edition, or \
7245         carry a canonical edition like `\"2026\"`)"
7246    )]
7247    EdicaoEmpty,
7248    #[error(
7249        ":edicao {edicao:?} is not a valid edition: {reason} (every \
7250         documented tatara-lisp edition is a 4-digit ASCII decimal \
7251         year — `\"2026\"` is the only edition currently minted; \
7252         future-introduced siblings will follow the same shape, peer \
7253         with Cargo's `[package] edition` grammar which every value \
7254         Cargo has ever accepted matches: `\"2015\"`, `\"2018\"`, \
7255         `\"2021\"`, `\"2024\"`. Without this gate the canonical \
7256         paste-from-doc footguns silently passed: a trailing space \
7257         (`\"2026 \"`) from a paste-from-doc, a CRLF (`\"2026\\n\"`) \
7258         from a paste-from-multiline-doc, a fullwidth-keyboard \
7259         look-alike (`\"2026\"`), a free-form non-year value \
7260         (`\"x\"`, `\"latest\"`, `\"nightly\"`), a leading non-digit \
7261         version-tag prefix (`\"v2026\"`, `\"e2026\"`), a \
7262         decimal-shaped pseudo-version (`\"2026.1\"`), or a \
7263         wrong-length numeric value (`\"26\"`, `\"202\"`, \
7264         `\"20260\"`) all landed as `(:edicao \"<garbage>\")` in the \
7265         rendered caixa.lisp and broke at the substrate's \
7266         build-time edition selector far from the source caixa.lisp; \
7267         omit the slot entirely to defer to the substrate's default \
7268         edition, or carry a canonical 4-digit ASCII decimal year \
7269         like `\"2026\"`)"
7270    )]
7271    EdicaoInvalid { edicao: String, reason: String },
7272}
7273
7274// Fold the five `Err(ManifestError::CodePath{Absolute,ParentEscape,
7275// NonLispExtension,NonComputeUnitYamlExtension,Duplicate} { slot,
7276// path: path.to_path_buf() })` four-line struct-variant wire-up sites at
7277// [`Caixa::validate_code_path_lists`]'s per-slot per-entry cascade onto
7278// one substrate-primitive family on the `ManifestError` envelope — the
7279// five open-coded ctor sites remaining on the `:bibliotecas` / `:exe` /
7280// `:servicos` code-path-list value-shape trajectory this envelope carries,
7281// and the family sibling of the peer [`crate::behavior::behavior_slot_path_ctors!`]
7282// (67c31ec) two-slot `{ slot: &'static str, path: PathBuf }` envelope on
7283// the [`crate::BehaviorError`] surface that keys off the exact same
7284// `(slot: &'static str, path: &Path)` argument tuple.
7285//
7286// The five wire-up sites this fold closes are the sandbox-shape
7287// absolute-path arm (`return Err(ManifestError::CodePathAbsolute { slot,
7288// path: path.to_path_buf() })` on the [`is_sandboxed_relative_path`]
7289// `PathShapeViolation::Absolute` branch), the sandbox-shape
7290// parent-escape arm (`return Err(ManifestError::CodePathParentEscape {
7291// slot, path: path.to_path_buf() })` on the sibling
7292// `PathShapeViolation::ParentEscape` branch), the LispSource
7293// terminating-extension arm (`return Err(ManifestError::CodePathNonLispExtension {
7294// slot, path: path.to_path_buf() })` on the `!is_lisp_extension(path)`
7295// branch of the `:bibliotecas` file-type gate), the ComputeUnitYaml
7296// compound-suffix arm (`return Err(ManifestError::CodePathNonComputeUnitYamlExtension
7297// { slot, path: path.to_path_buf() })` on the
7298// `!is_computeunit_yaml_extension(path)` branch of the `:servicos`
7299// file-type gate), and the cross-entry duplicate arm
7300// (`ManifestError::CodePathDuplicate { slot, path: path.to_path_buf() }`
7301// inside the closure passed to [`crate::render::insert_first_seen`]) —
7302// each opened the identical `ManifestError::CodePath* { slot,
7303// path: path.to_path_buf() }` four-line struct-literal against the same
7304// `(slot: &'static str, path: &Path)` local tuple, the exact "same
7305// block re-inlined at every consumer" shape the PRIME DIRECTIVE names
7306// as a bug. The variant discriminator is the only thing that varies
7307// between the five sites; the rest of the struct-literal is a
7308// byte-for-byte re-inline.
7309//
7310// The macro below generates one `#[must_use]` inherent constructor per
7311// variant of shape `fn <ctor>(slot: &'static str, path: &std::path::Path)
7312// -> Self`, so every wire-up site collapses onto one dispatch:
7313// `ManifestError::<ctor>(slot, path)`, byte-equal to the pre-lift
7314// struct-literal on the same `(&'static str, &Path)` fixture. The
7315// uniform two-field construction (`slot` verbatim as `&'static str`,
7316// `path.to_path_buf()`) is spelled once — inside the macro — rather
7317// than at every wire-up site. The `slot` parameter stays `&'static str`
7318// (not `&str`) so every arm continues to carry a program-lifetime
7319// `:bibliotecas` / `:exe` / `:servicos` author-key label — one of the
7320// three `&'static str` literals threaded through the outer per-slot
7321// iterator at [`Caixa::validate_code_path_lists`] — matching the
7322// enum-field type. A runtime-borrowed `&str` would silently downgrade
7323// the label lifetime and let a caller stash a non-`'static` borrow into
7324// the returned error. The `&Path` parameter accepts both
7325// `&Path` and `&PathBuf` (via Deref coercion), so every existing
7326// wire-up — each already binds `let path = Path::new(entry);` from the
7327// per-entry loop — threads through the ctor without a pre-conversion.
7328//
7329// Every future consumer that wants to construct one of these five
7330// variants outside the five in-crate wire-up sites (a deferred
7331// `feira validate --code-paths` per-caixa admission verb re-checking
7332// each declared `:bibliotecas` / `:exe` / `:servicos` entry against the
7333// same sandbox-shape + file-type + duplicate cascade, a future
7334// caixa-registry per-lacre code-path re-validator at lacre-resolve
7335// time, a per-`Caixa` overlay resolver rejecting an author-supplied
7336// code-path against a cluster-local snapshot) now reaches each variant
7337// through one call rather than re-inlining the four-line struct-literal
7338// in lockstep with the five in-crate wire-up sites.
7339macro_rules! manifest_code_path_slot_path_ctors {
7340    ($($ctor:ident => $variant:ident),* $(,)?) => {
7341        impl ManifestError {
7342            $(
7343                #[doc = concat!(
7344                    "Construct a [`ManifestError::",
7345                    stringify!($variant),
7346                    "`] naming the offending `:bibliotecas` / `:exe` / ",
7347                    "`:servicos` code-path list `slot` label and the ",
7348                    "offending entry `path`. Folds the uniform `Self::",
7349                    stringify!($variant),
7350                    " { slot, path: path.to_path_buf() }` two-field ",
7351                    "struct-literal onto one substrate primitive so ",
7352                    "every wire-up on this variant at ",
7353                    "[`Caixa::validate_code_path_lists`] reads through ",
7354                    "one dispatch rather than the pre-lift four-line ",
7355                    "open-coded block. The `slot` label threads verbatim ",
7356                    "from the outer per-slot iterator (one of the three ",
7357                    "code-path author-key `&'static str` consts) and the ",
7358                    "`path` from the per-entry inner iterator's ",
7359                    "`Path::new(entry)` binding."
7360                )]
7361                #[must_use]
7362                pub fn $ctor(slot: &'static str, path: &std::path::Path) -> Self {
7363                    Self::$variant {
7364                        slot,
7365                        path: path.to_path_buf(),
7366                    }
7367                }
7368            )*
7369        }
7370    };
7371}
7372
7373manifest_code_path_slot_path_ctors! {
7374    code_path_absolute => CodePathAbsolute,
7375    code_path_parent_escape => CodePathParentEscape,
7376    code_path_non_lisp_extension => CodePathNonLispExtension,
7377    code_path_non_computeunit_yaml_extension => CodePathNonComputeUnitYamlExtension,
7378    code_path_duplicate => CodePathDuplicate,
7379}
7380
7381// Fold the last `ManifestError::CodePathEmpty { slot: <&'static str> }` single-
7382// slot struct-variant wire-up site at [`Caixa::validate_code_path_lists`]'s
7383// per-slot [`PathShapeViolation::Empty`] arm onto one substrate primitive on
7384// `ManifestError` — the last open-coded single-slot `{ slot: &'static str }`
7385// struct-literal on the `:bibliotecas` / `:exe` / `:servicos` code-path-list
7386// value-shape trajectory this envelope carries, matching the peer five-variant
7387// [`manifest_code_path_slot_path_ctors!`] family fold (de11917, 5 variants on
7388// `{ slot: &'static str, path: PathBuf }`) already closed on the sibling
7389// two-slot envelope of the same `ManifestError`, and mirror-symmetric sibling
7390// of the peer [`crate::behavior::BehaviorError::empty_path`] (0e33b37,
7391// `EmptyPath { slot: &'static str }`) ctor on the sibling M2 `:behavior`
7392// envelope's identical one-slot shape. After this lift every wire-up on every
7393// `ManifestError` variant carried by [`Caixa::validate_code_path_lists`]'s
7394// per-slot [`PathShapeViolation`] cascade reads through one substrate-primitive
7395// ctor dispatch per typed variant rather than one macro closing four sites
7396// plus a hand-written empty-slot open-coding the fifth.
7397//
7398// A macro is not warranted on the one-variant envelope shape
7399// `{ slot: &'static str }` — unlike the peer five-variant
7400// `{ slot: &'static str, path: PathBuf }` shape the
7401// [`manifest_code_path_slot_path_ctors!`] macro closes — but the same
7402// substrate-primitive discipline applies: every future consumer that wants to
7403// construct a `CodePathEmpty` outside [`Caixa::validate_code_path_lists`] (a
7404// deferred `feira validate --code-paths` per-caixa admission verb re-checking
7405// each declared `:bibliotecas` / `:exe` / `:servicos` entry against the same
7406// sandbox-shape + file-type + duplicate cascade, a future caixa-registry
7407// per-lacre code-path re-validator at lacre-resolve time, a per-`Caixa`
7408// overlay resolver rejecting an author-supplied empty code-path against a
7409// cluster-local snapshot) reaches the variant through one call rather than
7410// re-inlining the one-line struct-literal in lockstep with the in-crate
7411// wire-up site.
7412//
7413// The `slot` parameter stays `&'static str` (not `&str`) so the constructor
7414// continues to carry a program-lifetime `:bibliotecas` / `:exe` / `:servicos`
7415// author-key label — one of the three `&'static str` literals threaded through
7416// the outer per-slot iterator at [`Caixa::validate_code_path_lists`] — matching
7417// the enum-field type and the peer [`manifest_code_path_slot_path_ctors!`]-
7418// generated arms' `slot: &'static str` parameter verbatim. A runtime-borrowed
7419// `&str` would silently downgrade the label lifetime and let a caller stash a
7420// non-`'static` borrow into the returned error. `const fn` preserves the
7421// zero-runtime-work property of the pre-lift struct-literal verbatim, matching
7422// the peer [`crate::behavior::BehaviorError::empty_path`] `const fn` on the
7423// sibling M2 envelope and the sibling
7424// [`crate::supervisor::supervisor_scalar_ctors!`] / peer
7425// [`crate::aplicacao::aplicacao_policy_scalar_ctors!`] `Copy`-scalar
7426// discipline on their sibling envelopes.
7427impl ManifestError {
7428    /// Construct a [`ManifestError::CodePathEmpty`] naming the offending
7429    /// `:bibliotecas` / `:exe` / `:servicos` code-path list `slot` label.
7430    /// Folds the uniform `Self::CodePathEmpty { slot }` one-field
7431    /// struct-literal onto one substrate primitive so the wire-up at
7432    /// [`Caixa::validate_code_path_lists`]'s per-slot
7433    /// [`PathShapeViolation::Empty`] arm on this variant reads through one
7434    /// dispatch rather than the pre-lift open-coded struct-literal block.
7435    /// Peer of the sibling [`ManifestError::code_path_absolute`] /
7436    /// [`ManifestError::code_path_parent_escape`] /
7437    /// [`ManifestError::code_path_non_lisp_extension`] /
7438    /// [`ManifestError::code_path_non_computeunit_yaml_extension`] /
7439    /// [`ManifestError::code_path_duplicate`] ctors the
7440    /// [`manifest_code_path_slot_path_ctors!`] macro closed on the paired
7441    /// two-slot `{ slot: &'static str, path: PathBuf }` envelope of the same
7442    /// `ManifestError`, and mirror-symmetric sibling of the peer
7443    /// [`crate::behavior::BehaviorError::empty_path`] ctor on the sibling M2
7444    /// `:behavior` envelope's identical one-slot shape — the per-slot
7445    /// [`PathShapeViolation`] cascade at [`Caixa::validate_code_path_lists`]
7446    /// now routes every arm through one substrate-primitive ctor per typed
7447    /// variant.
7448    #[must_use]
7449    pub const fn code_path_empty(slot: &'static str) -> Self {
7450        Self::CodePathEmpty { slot }
7451    }
7452}
7453
7454// Fold the ten `ManifestError::{Nome, NomeChartNameBudgetExceeded, Versao,
7455// Etiqueta, Autor, Repositorio, Descricao, Licenca, Edicao}Invalid +
7456// RestartWindowMalformed
7457// { <field>: <val>.to_string() | <val>.clone(), reason: <expr> }` wire-up
7458// sites at the per-axis [`Caixa::validate_*`] cascade onto one substrate-
7459// primitive family per typed variant — the direct sibling on the
7460// [`ManifestError`] envelope of the peer
7461// [`crate::aplicacao::aplicacao_field_reason_ctors!`] (981060b, 7 variants
7462// on `AplicacaoError` at `MembroCaixaInvalid` / `EntradaParaInvalid` /
7463// `EntradaHostInvalid` / `EntradaPathInvalid` / `PlacementClusterInvalid` /
7464// `PlacementAffinityInvalid` / `ShardKeyInvalid`) on the M3 mesh side, and
7465// of the peer [`crate::dep::dep_nome_axis_reason_ctors!`] (5621f8a,
7466// 3 variants on `DepError` at `VersaoInvalid` / `FonteRepoShape` /
7467// `CaracteristicaInvalid`) on the sibling `:deps` envelope's mirror-
7468// symmetric `{ nome: String, <axis>: String, reason: String }` three-slot
7469// shape (the `nome` axis added at the per-dep-owned altitude). Every one
7470// of the peer four-family `LayoutError` ctor set
7471// ([`crate::layout::layout_violation_ctors!`] 131ca0d — 16 variants on
7472// `{ caixa, issue }`, [`crate::layout::layout_slot_kind_ctors!`] 0419438
7473// — 4 variants on `{ caixa, kind, slots }`,
7474// [`crate::LayoutError::missing_entry`] 1b09f9d — 1 variant on
7475// `{ kind, path }`, [`crate::layout::layout_nome_only_ctors!`] 3fe3dd7 —
7476// 6 variants on `<Variant>(String)`) and the peer three
7477// [`crate::limits::limits_codec_value_*_ctors!`] codec families (81c856c)
7478// each carry the same discipline on their sibling envelopes.
7479//
7480// The ten variants share the identical `{ <field>: String,
7481// reason: String }` two-slot shape:
7482//   - `NomeInvalid { nome, reason }` at [`Caixa::validate_nome`]
7483//     (`|reason| ManifestError::NomeInvalid { nome: nome.to_string(),
7484//     reason }` inside [`crate::render::require_valid_dns_1123_label`]'s
7485//     `on_invalid` bracket-closure slot);
7486//   - `NomeChartNameBudgetExceeded { nome, reason }` at
7487//     [`Caixa::validate_nome_chart_name_budget`]
7488//     (`|reason| ManifestError::NomeChartNameBudgetExceeded { nome:
7489//     nome.to_string(), reason }` after
7490//     [`crate::render::is_lareira_chart_name_shape`] rejects the offending
7491//     `:nome`);
7492//   - `VersaoInvalid { versao, reason }` at [`Caixa::validate_versao`]
7493//     (`|e| ManifestError::VersaoInvalid { versao: versao.to_string(),
7494//     reason: e.to_string() }` after [`semver::Version::parse`] rejects
7495//     the offending `:versao`);
7496//   - `EtiquetaInvalid { etiqueta, reason }` at
7497//     [`Caixa::validate_etiquetas`]
7498//     (`|reason| ManifestError::EtiquetaInvalid { etiqueta:
7499//     etiqueta.clone(), reason }` after
7500//     [`crate::render::is_chart_keyword_shape`] rejects the offending
7501//     `:etiquetas` entry);
7502//   - `AutorInvalid { autor, reason }` at [`Caixa::validate_autores`]
7503//     (`|reason| ManifestError::AutorInvalid { autor: autor.clone(),
7504//     reason }` after [`crate::render::is_chart_maintainer_name_shape`]
7505//     rejects the offending `:autores` entry);
7506//   - `RepositorioInvalid { repositorio, reason }` at
7507//     [`Caixa::validate_repositorio`]
7508//     (`|reason| ManifestError::RepositorioInvalid { repositorio:
7509//     s.to_string(), reason }` after
7510//     [`crate::render::is_git_repo_url`] rejects the offending
7511//     `:repositorio`);
7512//   - `DescricaoInvalid { descricao, reason }` at
7513//     [`Caixa::validate_descricao`]
7514//     (`|reason| ManifestError::DescricaoInvalid { descricao:
7515//     s.to_string(), reason }` after
7516//     [`crate::render::is_chart_description_shape`] rejects the offending
7517//     `:descricao`);
7518//   - `LicencaInvalid { licenca, reason }` at [`Caixa::validate_licenca`]
7519//     (`|reason| ManifestError::LicencaInvalid { licenca: s.to_string(),
7520//     reason }` after [`crate::render::is_spdx_expression_shape`] rejects
7521//     the offending `:licenca`);
7522//   - `EdicaoInvalid { edicao, reason }` at [`Caixa::validate_edicao`]
7523//     (`return Err(ManifestError::EdicaoInvalid { edicao: s.to_string(),
7524//     reason: "must be a 4-digit ASCII decimal year (canonical
7525//     \"2026\")".to_string() })` on the direct year-shape arm);
7526//   - `RestartWindowMalformed { restart_window, reason }` at
7527//     [`Caixa::validate_restart_window`]
7528//     (`|reason| ManifestError::RestartWindowMalformed { restart_window:
7529//     s.to_string(), reason }` after
7530//     [`crate::supervisor::duration_codec::parse`] rejects the offending
7531//     `:restart-window` raw string).
7532//
7533// Each opened the identical four-line
7534// `ManifestError::<Variant> { <field>: <val>.to_string() | .clone(),
7535// reason: <expr> }` struct-literal against the caller-side `<field>: &str`
7536// / `<field>: &String` local — the exact "same block re-inlined at every
7537// consumer" shape the PRIME DIRECTIVE names as a bug, on the same altitude
7538// the peer `aplicacao_field_reason_ctors!` / `dep_nome_axis_reason_ctors!`
7539// / `LayoutError` / `LimitsError` / `BehaviorError` / `UpgradeError`
7540// families each closed on their sibling envelopes.
7541//
7542// The macro below generates one `#[must_use]` inherent constructor per
7543// variant of shape `fn <ctor>(<field>: &str, reason: impl Into<String>)
7544// -> Self`, collapsing every site onto one dispatch per arm:
7545// `ManifestError::<ctor>(<val>, <reason>)`, byte-equal to the pre-lift
7546// struct-literal on the same `(<field>, reason)` pair. The uniform
7547// two-field construction (`<field>: <field>.to_string()`,
7548// `reason: reason.into()`) is spelled once — inside the macro — rather
7549// than at every wire-up site. The `reason: impl Into<String>` bound
7550// accepts owned `String` (the parser-shaped reason every predicate
7551// returns via `Result<(), String>`; the `e.to_string()` result the
7552// `semver::Version::parse` arm passes; the literal `"…".to_string()` the
7553// `EdicaoInvalid` direct arm passes), `&str` literals, and `format!(…)`
7554// outputs verbatim so no wire-up site changes its per-arm diagnostic
7555// shape at the lift, matching the peer
7556// [`crate::aplicacao::aplicacao_field_reason_ctors!`] and
7557// [`crate::dep::dep_nome_axis_reason_ctors!`] bounds on the sibling
7558// two- and three-slot envelopes. The `<field>: &str` parameter accepts
7559// both `&str` (from the [`Caixa::nome`] / [`Caixa::versao`] /
7560// [`Caixa::repositorio`] / [`Caixa::descricao`] / [`Caixa::licenca`] /
7561// [`Caixa::edicao`] accessors) and `&String` (from the
7562// [`Caixa::etiquetas`] / [`Caixa::autores`] slice iterators) via Deref
7563// coercion, so every existing wire-up threads through the ctor without a
7564// pre-conversion. `#[must_use]` fires a compile warning at any wire-up
7565// that mistakenly discards the constructed error rather than routing it
7566// through `return Err(…)` / `.map_err(…)` / a closure return.
7567//
7568// Every future consumer that wants to construct one of these ten
7569// variants outside the current in-crate wire-up sites (a deferred
7570// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's per-manifest-axis
7571// admission validators re-checking each declared identity / metadata
7572// axis against a cluster-local snapshot, a future `feira validate
7573// --manifest` per-caixa admission verb re-running the same
7574// value-shape gates on demand, a per-lacre overlay resolver rejecting
7575// an author-supplied manifest override against a cluster-local snapshot
7576// the M4 CR materializer projects, a future
7577// `caixa-registry` per-lacre re-validator at lacre-resolve time
7578// re-checking each declared axis against the same predicates) now
7579// reaches each variant through one call rather than re-inlining the
7580// four-line struct-literal in lockstep with the ten in-crate wire-up
7581// sites.
7582macro_rules! manifest_field_reason_ctors {
7583    ($($ctor:ident => $variant:ident { $field:ident }),* $(,)?) => {
7584        impl ManifestError {
7585            $(
7586                #[doc = concat!(
7587                    "Construct a [`ManifestError::",
7588                    stringify!($variant),
7589                    "`] naming the offending `",
7590                    stringify!($field),
7591                    "` under the given `reason`. Folds the uniform ",
7592                    "`Self::",
7593                    stringify!($variant),
7594                    " { ",
7595                    stringify!($field),
7596                    ": ",
7597                    stringify!($field),
7598                    ".to_string(), reason: reason.into() }` two-slot ",
7599                    "construction onto one substrate primitive so every ",
7600                    "wire-up on this variant reads through one dispatch ",
7601                    "rather than the pre-lift four-line struct-literal ",
7602                    "block. `reason` accepts owned `String`, `&str` ",
7603                    "literals, and `format!(…)` outputs through the ",
7604                    "`impl Into<String>` bound; the `",
7605                    stringify!($field),
7606                    ": &str` parameter accepts both `&str` and `&String` ",
7607                    "via Deref coercion."
7608                )]
7609                #[must_use]
7610                pub fn $ctor($field: &str, reason: impl Into<String>) -> Self {
7611                    Self::$variant {
7612                        $field: $field.to_string(),
7613                        reason: reason.into(),
7614                    }
7615                }
7616            )*
7617        }
7618    };
7619}
7620
7621manifest_field_reason_ctors! {
7622    nome_invalid => NomeInvalid { nome },
7623    nome_chart_name_budget_exceeded => NomeChartNameBudgetExceeded { nome },
7624    versao_invalid => VersaoInvalid { versao },
7625    etiqueta_invalid => EtiquetaInvalid { etiqueta },
7626    autor_invalid => AutorInvalid { autor },
7627    repositorio_invalid => RepositorioInvalid { repositorio },
7628    descricao_invalid => DescricaoInvalid { descricao },
7629    licenca_invalid => LicencaInvalid { licenca },
7630    edicao_invalid => EdicaoInvalid { edicao },
7631    restart_window_malformed => RestartWindowMalformed { restart_window },
7632}
7633
7634// Fold the two `ManifestError::{EtiquetaDuplicate, AutorDuplicate}
7635// { <field>: <val>.clone() }` single-`String`-slot wire-up sites at
7636// [`Caixa::validate_etiquetas`] and [`Caixa::validate_autores`] onto one
7637// substrate-primitive family per typed variant — the direct sibling on
7638// the [`ManifestError`] envelope of the peer
7639// [`crate::aplicacao::aplicacao_caixa_only_ctors!`] (d9f6867, 4 variants
7640// on `AplicacaoError` at `ContratoMemberMissing` / `MembroVersaoEmpty` /
7641// `MembroDuplicate` / `MembroIsSelfAplicacao` on the `{ caixa: String }`
7642// shape) and [`crate::aplicacao::aplicacao_path_only_ctors!`] (3ba8de6,
7643// 2 variants on `AplicacaoError` at `EntradaPathNotAbsolute` /
7644// `EntradaPathDuplicate` on the `{ path: String }` shape) on the sibling
7645// M3 mesh `AplicacaoError` envelope, and of the peer
7646// [`crate::supervisor::supervisor_caixa_only_ctors!`] (db09650, 3 variants
7647// on the sibling M2 `SupervisorError` envelope's `{ caixa: String }`
7648// shape), [`crate::dep::dep_nome_only_ctors!`] (792aa92, 5 variants on
7649// `DepError { nome: String }`), and [`crate::upgrade::upgrade_script_only_ctors!`]
7650// (7468ca9, 3 variants on `UpgradeError { script: PathBuf }`) folds on
7651// the sibling envelopes — the last two open-coded single-slot
7652// `{ <field>: String }` struct-literal sites on `ManifestError` fold
7653// onto one substrate primitive per typed variant, matching the
7654// "one substrate primitive per typed variant on the single-slot
7655// `{ <ident>: String }` envelope shape" fold discipline every peer
7656// per-Caixa-identity family already carries.
7657//
7658// Both wire-up sites — one at [`Caixa::validate_etiquetas`]'s per-entry
7659// [`crate::render::insert_first_seen`] dedup closure
7660// (`|| ManifestError::EtiquetaDuplicate { etiqueta: etiqueta.clone() }`
7661// against the per-`:etiquetas` `&String` loop head) and one at
7662// [`Caixa::validate_autores`]'s per-entry [`crate::render::insert_first_seen`]
7663// dedup closure (`|| ManifestError::AutorDuplicate
7664// { autor: autor.clone() }` against the per-`:autores` `&String` loop
7665// head) — opened the identical `ManifestError::<Variant>Duplicate
7666// { <field>: <val>.clone() }` three-line struct-literal against a
7667// caller-side `&String`, the exact "same block re-inlined at every
7668// consumer" shape the PRIME DIRECTIVE names as a bug. The two variants
7669// share one `{ <field>: String }` shape, so the fold routes each wire-up
7670// site through one dispatch per typed variant.
7671//
7672// The macro below generates one `#[must_use]` inherent constructor per
7673// variant of shape `fn <ctor>(<field>: &str) -> ManifestError`, so every
7674// wire-up site collapses onto one dispatch:
7675// `ManifestError::<ctor>(<&str>)`, byte-equal to the pre-lift
7676// struct-literal on the same `&str` fixture. The uniform one-field
7677// construction (`<field>: <field>.to_string()`) is spelled once — inside
7678// the macro — rather than at every wire-up site. The `<field>: &str`
7679// parameter accepts both `&str` and `&String` (via Deref coercion), so
7680// each existing dedup-closure wire-up threading `<val>.as_str()` — or a
7681// bare `&String` head — through the ctor routes through one dispatch
7682// without a pre-conversion, and the `.clone()` the pre-lift wire-up
7683// carried at the closure body folds into the ctor's canonical
7684// `.to_string()` (byte-equal on the same underlying bytes). Every
7685// constructor is `#[must_use]` so a caller who mistakenly discards the
7686// constructed error trips a compile warning at the wire-up site.
7687//
7688// Every future consumer that wants to construct one of these two
7689// variants outside the current in-crate wire-up sites — a deferred
7690// `caixa.pleme.io/v1alpha1/Caixa` CR materializer's admission webhook
7691// re-checking one added/renamed `:etiquetas` / `:autores` entry against
7692// the same dedup axis, a future `feira validate --etiquetas` /
7693// `--autores` per-caixa admission verb re-running the same per-entry
7694// dedup gate on demand, a per-lacre overlay resolver rejecting an
7695// author-supplied duplicate `:etiquetas` / `:autores` entry against a
7696// cluster-local snapshot the M4 CR materializer projects, a future
7697// `caixa-registry` per-lacre re-validator at lacre-resolve time
7698// re-checking each declared list against the same dedup predicate — now
7699// reaches each variant through one call rather than re-inlining the
7700// three-line struct-literal in lockstep with the two in-crate wire-up
7701// sites.
7702macro_rules! manifest_field_only_ctors {
7703    ($($ctor:ident => $variant:ident { $field:ident }),* $(,)?) => {
7704        impl ManifestError {
7705            $(
7706                #[doc = concat!(
7707                    "Construct a [`ManifestError::",
7708                    stringify!($variant),
7709                    "`] naming the offending `",
7710                    stringify!($field),
7711                    "` entry. Folds the uniform `Self::",
7712                    stringify!($variant),
7713                    " { ",
7714                    stringify!($field),
7715                    ": ",
7716                    stringify!($field),
7717                    ".to_string() }` one-field struct-literal onto one ",
7718                    "substrate primitive so every wire-up on this variant ",
7719                    "reads through one dispatch rather than the pre-lift ",
7720                    "three-line open-coded struct-literal block. The `",
7721                    stringify!($field),
7722                    ": &str` parameter accepts both `&str` and `&String` ",
7723                    "via Deref coercion."
7724                )]
7725                #[must_use]
7726                pub fn $ctor($field: &str) -> Self {
7727                    Self::$variant {
7728                        $field: $field.to_string(),
7729                    }
7730                }
7731            )*
7732        }
7733    };
7734}
7735
7736manifest_field_only_ctors! {
7737    etiqueta_duplicate => EtiquetaDuplicate { etiqueta },
7738    autor_duplicate => AutorDuplicate { autor },
7739}
7740
7741#[cfg(test)]
7742mod tests {
7743    use super::*;
7744
7745    #[test]
7746    fn template_round_trips() {
7747        let src = Caixa::template("demo");
7748        let c = Caixa::from_lisp(&src).expect("template must parse");
7749        assert_eq!(c.nome, "demo");
7750        assert_eq!(c.versao, "0.1.0");
7751        assert_eq!(c.kind, CaixaKind::Biblioteca);
7752        assert_eq!(c.bibliotecas, vec!["lib/demo.lisp".to_string()]);
7753        assert!(c.deps.is_empty());
7754        assert!(c.deps_dev.is_empty());
7755    }
7756
7757    #[test]
7758    fn caixa_universal_axis_scalar_accessor_pair_is_const_fn() {
7759        // Fail-before-pass-after pin on [`Caixa::nome`] +
7760        // [`Caixa::versao`]'s `const`-eval-surface posture. Each
7761        // accessor projects the top-level manifest's per-`:nome` /
7762        // per-`:versao` [`String`] storage through the `pub const fn`
7763        // [`String::as_str`] (const-stable since Rust 1.87, well within
7764        // the workspace MSRV) — any future accidental downgrade to
7765        // non-`const` fails the corresponding `<name>_via_const_fn`
7766        // wrapper at caixa-core build time with E0015 (`cannot call
7767        // non-const method`), strictly stronger than a runtime
7768        // `assert!`. Sibling of the peer per-M2/M3-slot `String → &str`
7769        // scalar-accessor family pins on the sibling `const`-eval-
7770        // surface passes ([`crate::CaixaVersion::as_str`] at the
7771        // typed-newtype wrapper, [`crate::aplicacao::Membro::nome`] /
7772        // [`crate::aplicacao::Membro::versao_requirement`] at the M3
7773        // membership axis, [`crate::aplicacao::Entrada::hostname`] /
7774        // [`crate::aplicacao::Entrada::destination`] at the M3 ingress
7775        // axis, [`crate::supervisor::ChildSpec::nome`] /
7776        // [`crate::supervisor::ChildSpec::versao_requirement`] at the
7777        // M2 supervisor-tree axis,
7778        // [`crate::upgrade::UpgradeFromEntry::prior_versao`] at the M2
7779        // upgrade axis, [`crate::dep::Dep::nome`] /
7780        // [`crate::dep::Dep::versao_requirement`] at the dep-graph
7781        // axis, and the per-`:contratos`
7782        // [`crate::aplicacao::WitContract::source`] /
7783        // [`crate::aplicacao::WitContract::destination`] /
7784        // [`crate::aplicacao::WitContract::world_ref`] trio the
7785        // sibling pin at 279823b already anchors).
7786        const fn nome_via_const_fn(c: &Caixa) -> &str {
7787            c.nome()
7788        }
7789        const fn versao_via_const_fn(c: &Caixa) -> &str {
7790            c.versao()
7791        }
7792        let src = Caixa::template("demo");
7793        let c = Caixa::from_lisp(&src).expect("template must parse");
7794        assert_eq!(nome_via_const_fn(&c), c.nome());
7795        assert_eq!(versao_via_const_fn(&c), c.versao());
7796        assert_eq!(c.nome(), "demo");
7797        assert_eq!(c.versao(), "0.1.0");
7798    }
7799
7800    #[test]
7801    fn caixa_option_string_scalar_accessor_family_is_const_fn() {
7802        // Fail-before-pass-after pin on the five per-`Caixa`
7803        // `Option<String> → Option<&str>` scalar accessors
7804        // ([`Caixa::licenca`] / [`Caixa::repositorio`] /
7805        // [`Caixa::descricao`] / [`Caixa::edicao`] on the top-level
7806        // manifest's optional universal-axis surface, plus
7807        // [`Caixa::restart_window`] on the M2 supervisor-tree
7808        // per-`SupervisorSpec` peer raw-window-string projection axis).
7809        // Each accessor destructures the typed slot's `Option<String>`
7810        // storage through the `match &self.<field> { Some(s) =>
7811        // Some(s.as_str()), None => None }` shape — routing through
7812        // [`String::as_str`] (const-stable since Rust 1.87, well within
7813        // the workspace MSRV) rather than the non-const
7814        // [`Option::as_deref`] the pre-lift bodies carried — and any
7815        // future accidental downgrade to non-`const` fails the
7816        // corresponding `<name>_via_const_fn` wrapper at caixa-core
7817        // build time with E0015 (`cannot call non-const method`),
7818        // strictly stronger than a runtime `assert!` and strictly
7819        // stronger than a module-scope `const _: () = assert!(…)` pin
7820        // (which cannot be formed on a `&Caixa` fixture because the
7821        // type's `String` / `Option<String>` carriers rule out
7822        // `const`-context value construction; the `const fn` wrapper
7823        // is the load-bearing shape that side-steps the destructor-in-
7824        // const restriction on the value axis while still pinning the
7825        // `const`-fn posture on the callee — mirror of the sibling
7826        // [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
7827        // pin's discipline verbatim on the peer non-`Option`
7828        // `String → &str` axis at the same struct).
7829        //
7830        // Peer of the sibling per-M2/M3-slot `Option<String> →
7831        // Option<&str>` accessor family pin
7832        // [`m3_option_string_scalar_accessor_family_is_const_fn`] on
7833        // the M3 mesh-slot atom axes ([`WitContract::endpoint`] /
7834        // [`WitContract::subject`] / [`WitContract::slot`] on the
7835        // per-`:contratos` payload-carrier trio,
7836        // [`Placement::shard_key`] / [`Placement::affinity`] on the
7837        // per-`:placement` optional-scalar pair).
7838        const fn licenca_via_const_fn(c: &Caixa) -> Option<&str> {
7839            c.licenca()
7840        }
7841        const fn repositorio_via_const_fn(c: &Caixa) -> Option<&str> {
7842            c.repositorio()
7843        }
7844        const fn descricao_via_const_fn(c: &Caixa) -> Option<&str> {
7845            c.descricao()
7846        }
7847        const fn edicao_via_const_fn(c: &Caixa) -> Option<&str> {
7848            c.edicao()
7849        }
7850        const fn restart_window_via_const_fn(c: &Caixa) -> Option<&str> {
7851            c.restart_window()
7852        }
7853        // Sweep both the `Some`-carrying arm (author-declared slot,
7854        // the byte-string projection payload) and the `None`-carrying
7855        // arm (author-omitted slot, the default-path projection) on
7856        // every accessor so the `const fn` wrapper family pins each
7857        // axis's canonical two-arm partition through the same const
7858        // dispatch as the runtime path.
7859        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7860        c1.licenca = Some("MIT".to_string());
7861        c1.repositorio = Some("https://github.com/pleme-io/demo".to_string());
7862        c1.descricao = Some("demo caixa".to_string());
7863        c1.edicao = Some("2024".to_string());
7864        c1.restart_window = Some("60s".to_string());
7865        assert_eq!(licenca_via_const_fn(&c1), c1.licenca());
7866        assert_eq!(repositorio_via_const_fn(&c1), c1.repositorio());
7867        assert_eq!(descricao_via_const_fn(&c1), c1.descricao());
7868        assert_eq!(edicao_via_const_fn(&c1), c1.edicao());
7869        assert_eq!(restart_window_via_const_fn(&c1), c1.restart_window());
7870        assert_eq!(c1.licenca(), Some("MIT"));
7871        assert_eq!(c1.repositorio(), Some("https://github.com/pleme-io/demo"));
7872        assert_eq!(c1.descricao(), Some("demo caixa"));
7873        assert_eq!(c1.edicao(), Some("2024"));
7874        assert_eq!(c1.restart_window(), Some("60s"));
7875        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7876        c2.licenca = None;
7877        c2.repositorio = None;
7878        c2.descricao = None;
7879        c2.edicao = None;
7880        c2.restart_window = None;
7881        assert_eq!(licenca_via_const_fn(&c2), None);
7882        assert_eq!(repositorio_via_const_fn(&c2), None);
7883        assert_eq!(descricao_via_const_fn(&c2), None);
7884        assert_eq!(edicao_via_const_fn(&c2), None);
7885        assert_eq!(restart_window_via_const_fn(&c2), None);
7886    }
7887
7888    #[test]
7889    fn caixa_outer_copy_return_accessor_pair_is_const_fn() {
7890        // Fail-before-pass-after pin on the two outer-[`Caixa`]
7891        // `Copy`-return accessors — [`Caixa::kind`] on the required
7892        // [`CaixaKind`] enum-discriminant axis and [`Caixa::estrategia`]
7893        // on the M2 supervisor-tree flat-spread `Option<RestartStrategy>`
7894        // axis. Both accessors project a `Copy`-carrier field
7895        // (`CaixaKind: Copy` at caixa-core/src/kind.rs:17,
7896        // `RestartStrategy: Copy` at caixa-core/src/supervisor.rs:33 →
7897        // `Option<RestartStrategy>: Copy`) by value through a bare
7898        // `self.<field>` field-access — no dispatch, no destructor, no
7899        // heap. Any future accidental downgrade to non-`const` fails
7900        // the corresponding `<name>_via_const_fn` wrapper at caixa-core
7901        // build time with E0015 (`cannot call non-const method`),
7902        // strictly stronger than a runtime `assert!` and strictly
7903        // stronger than a module-scope `const _: () = assert!(…)` pin
7904        // (which cannot be formed on a `&Caixa` fixture because the
7905        // type's `String` / `Vec` / `Option<Composite>` carriers rule
7906        // out `const`-context value construction; the `const fn`
7907        // wrapper is the load-bearing shape that side-steps the
7908        // destructor-in-const restriction on the value axis while still
7909        // pinning the `const`-fn posture on the callee — mirror of the
7910        // sibling [`caixa_universal_axis_scalar_accessor_pair_is_const_fn`]
7911        // + [`caixa_option_string_scalar_accessor_family_is_const_fn`]
7912        // pins' discipline verbatim on the peer outer-`Caixa`
7913        // `String → &str` + `Option<String> → Option<&str>` axes at the
7914        // same struct).
7915        //
7916        // Peer of the sibling per-M2/M3-slot `Copy`-return accessor pin
7917        // family on the inner-altitude nested-spec typed-slot
7918        // discriminator axes: [`crate::supervisor::SupervisorSpec::estrategia`]
7919        // + [`crate::supervisor::ChildSpec::restart`] on the M2
7920        // supervisor-tree axis (pinned at 152c868), and
7921        // [`crate::aplicacao::Placement::estrategia`] +
7922        // [`crate::aplicacao::Entrada::port`] on the M3 mesh-slot axis
7923        // (pinned at bafa004) — the outer-`Caixa` altitude is the last
7924        // unlifted altitude for the `Copy`-return-accessor family.
7925        const fn kind_via_const_fn(c: &Caixa) -> CaixaKind {
7926            c.kind()
7927        }
7928        const fn estrategia_via_const_fn(c: &Caixa) -> Option<crate::supervisor::RestartStrategy> {
7929            c.estrategia()
7930        }
7931        // Sweep every arm of both discriminant partitions the accessors
7932        // fan on — every [`CaixaKind`] variant the six-arm required
7933        // discriminant carries (Biblioteca / Binario / Servico /
7934        // Supervisor / Aplicacao / Acao) and both arms of the
7935        // [`Option<RestartStrategy>`] flat-spread supervisor-tree slot
7936        // (`Some(<strategy>)` on an author-declared supervisor and
7937        // `None` on the author-omitted default arm every non-Supervisor
7938        // caixa carries by `#[serde(default)]`) — so the `const fn`
7939        // wrapper family pins the closed-set partition through the
7940        // same const dispatch as the runtime path.
7941        let mut c1 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7942        c1.kind = CaixaKind::Servico;
7943        c1.estrategia = Some(crate::supervisor::RestartStrategy::OneForAll);
7944        assert_eq!(kind_via_const_fn(&c1), c1.kind());
7945        assert_eq!(estrategia_via_const_fn(&c1), c1.estrategia());
7946        assert_eq!(c1.kind(), CaixaKind::Servico);
7947        assert_eq!(
7948            c1.estrategia(),
7949            Some(crate::supervisor::RestartStrategy::OneForAll)
7950        );
7951        let mut c2 = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7952        c2.kind = CaixaKind::Aplicacao;
7953        c2.estrategia = None;
7954        assert_eq!(kind_via_const_fn(&c2), CaixaKind::Aplicacao);
7955        assert_eq!(estrategia_via_const_fn(&c2), None);
7956        // Anchor the remaining discriminant arms so any future
7957        // reordering of [`CaixaKind`]'s six-variant enum surfaces
7958        // through the wrapper dispatch, not just through the direct
7959        // method call.
7960        for kind in [
7961            CaixaKind::Biblioteca,
7962            CaixaKind::Binario,
7963            CaixaKind::Servico,
7964            CaixaKind::Supervisor,
7965            CaixaKind::Aplicacao,
7966            CaixaKind::Acao,
7967        ] {
7968            let mut c = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
7969            c.kind = kind;
7970            assert_eq!(kind_via_const_fn(&c), kind);
7971        }
7972    }
7973
7974    #[test]
7975    fn caixa_outer_string_slice_return_accessor_family_is_const_fn() {
7976        // Fail-before-pass-after pin on the five outer-[`Caixa`]
7977        // `Vec<String> → &[String]` slice-return accessors on the
7978        // universal-axis surface — [`Caixa::autores`] / [`Caixa::etiquetas`]
7979        // / [`Caixa::bibliotecas`] / [`Caixa::exe`] / [`Caixa::servicos`].
7980        // Each body is a bare `self.<field>.as_slice()` dispatch through
7981        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
7982        // the workspace MSRV). Any future accidental downgrade to
7983        // non-`const` fails the corresponding `<name>_via_const_fn`
7984        // wrapper at caixa-core build time with E0015 (`cannot call
7985        // non-const method`) — mirror of the sibling
7986        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] pin's
7987        // discipline on the peer outer-`Caixa` `Copy`-return accessor
7988        // axis, and peer of the sibling composite-carrier slice-return
7989        // pin below on the peer outer-`Caixa` composite-slice axis.
7990        const fn autores_via_const_fn(c: &Caixa) -> &[String] {
7991            c.autores()
7992        }
7993        const fn etiquetas_via_const_fn(c: &Caixa) -> &[String] {
7994            c.etiquetas()
7995        }
7996        const fn bibliotecas_via_const_fn(c: &Caixa) -> &[String] {
7997            c.bibliotecas()
7998        }
7999        const fn exe_via_const_fn(c: &Caixa) -> &[String] {
8000            c.exe()
8001        }
8002        const fn servicos_via_const_fn(c: &Caixa) -> &[String] {
8003            c.servicos()
8004        }
8005        // Sweep the empty arm (`autores` / `etiquetas` / `exe` /
8006        // `servicos` — the template's `Vec::new()` default) and the
8007        // populated arm (mutated below) on every accessor so the
8008        // `const fn` wrapper family pins each axis's two-arm partition
8009        // through the same const dispatch as the runtime path.
8010        // [`Caixa::template`] seeds `lib/demo.lisp` into `:bibliotecas`,
8011        // so that arm's "empty" fixture is the populated arm the
8012        // mutation sweep covers.
8013        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8014        assert!(autores_via_const_fn(&c_empty).is_empty());
8015        assert!(etiquetas_via_const_fn(&c_empty).is_empty());
8016        assert!(exe_via_const_fn(&c_empty).is_empty());
8017        assert!(servicos_via_const_fn(&c_empty).is_empty());
8018        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8019        c_full.autores = vec!["ada".to_string(), "erlang".to_string()];
8020        c_full.etiquetas = vec!["compounding".to_string()];
8021        c_full.bibliotecas = vec!["lib/one.lisp".to_string(), "lib/two.lisp".to_string()];
8022        c_full.exe = vec!["exe/cli.lisp".to_string()];
8023        c_full.servicos = vec!["servicos/one.computeunit.yaml".to_string()];
8024        assert_eq!(autores_via_const_fn(&c_full), c_full.autores());
8025        assert_eq!(autores_via_const_fn(&c_full), &["ada", "erlang"]);
8026        assert_eq!(etiquetas_via_const_fn(&c_full), c_full.etiquetas());
8027        assert_eq!(etiquetas_via_const_fn(&c_full), &["compounding"]);
8028        assert_eq!(bibliotecas_via_const_fn(&c_full), c_full.bibliotecas());
8029        assert_eq!(
8030            bibliotecas_via_const_fn(&c_full),
8031            &["lib/one.lisp", "lib/two.lisp"]
8032        );
8033        assert_eq!(exe_via_const_fn(&c_full), c_full.exe());
8034        assert_eq!(exe_via_const_fn(&c_full), &["exe/cli.lisp"]);
8035        assert_eq!(servicos_via_const_fn(&c_full), c_full.servicos());
8036        assert_eq!(
8037            servicos_via_const_fn(&c_full),
8038            &["servicos/one.computeunit.yaml"]
8039        );
8040    }
8041
8042    #[test]
8043    fn caixa_outer_composite_slice_return_accessor_family_is_const_fn() {
8044        // Fail-before-pass-after pin on the six outer-[`Caixa`] composite-
8045        // carrier `Vec<T> → &[T]` slice-return accessors — [`Caixa::deps`]
8046        // / [`Caixa::deps_dev`] on the dep-graph axis,
8047        // [`Caixa::upgrade_from`] on the M2 appup axis, [`Caixa::children`]
8048        // on the M2 supervisor-tree axis, and [`Caixa::membros`] /
8049        // [`Caixa::contratos`] on the M3 mesh-slot axis. Each body is a
8050        // bare `self.<field>.as_slice()` dispatch through
8051        // [`Vec::as_slice`] (const-stable since Rust 1.87, well within
8052        // the workspace MSRV) — peer of the sibling `String`-payload
8053        // slice-return pin above on the peer outer-`Caixa` universal-
8054        // axis surface, and peer of the sibling inner-composite-
8055        // altitude reference-return pin family
8056        // [`crate::aplicacao::tests::m3_aplicacao_spec_reference_return_accessor_family_is_const_fn`]
8057        // + [`crate::supervisor::tests::supervisor_children_slice_return_accessor_is_const_fn`]
8058        // + [`crate::upgrade::tests::upgrade_from_entry_instructions_slice_return_accessor_is_const_fn`]
8059        // (all pinned at 0b23e0f).
8060        const fn deps_via_const_fn(c: &Caixa) -> &[Dep] {
8061            c.deps()
8062        }
8063        const fn deps_dev_via_const_fn(c: &Caixa) -> &[Dep] {
8064            c.deps_dev()
8065        }
8066        const fn upgrade_from_via_const_fn(c: &Caixa) -> &[UpgradeFromEntry] {
8067            c.upgrade_from()
8068        }
8069        const fn children_via_const_fn(c: &Caixa) -> &[crate::supervisor::ChildSpec] {
8070            c.children()
8071        }
8072        const fn membros_via_const_fn(c: &Caixa) -> &[crate::aplicacao::Membro] {
8073            c.membros()
8074        }
8075        const fn contratos_via_const_fn(c: &Caixa) -> &[crate::aplicacao::WitContract] {
8076            c.contratos()
8077        }
8078        // Empty-arm sweep on all six composite-carrier axes — every
8079        // `Caixa::template` starts with `Vec::new()` on each.
8080        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8081        assert!(deps_via_const_fn(&c_empty).is_empty());
8082        assert!(deps_dev_via_const_fn(&c_empty).is_empty());
8083        assert!(upgrade_from_via_const_fn(&c_empty).is_empty());
8084        assert!(children_via_const_fn(&c_empty).is_empty());
8085        assert!(membros_via_const_fn(&c_empty).is_empty());
8086        assert!(contratos_via_const_fn(&c_empty).is_empty());
8087        // Populate `:membros` / `:contratos` directly via struct literals
8088        // — the parser-side validation path fans on `:kind`-gated cross-
8089        // slot invariants irrelevant to the accessor dispatch under test.
8090        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8091        c_full.membros = vec![
8092            crate::aplicacao::Membro {
8093                caixa: "demo-a".to_string(),
8094                versao: "^0.1.0".to_string(),
8095            },
8096            crate::aplicacao::Membro {
8097                caixa: "demo-b".to_string(),
8098                versao: "^0.2.0".to_string(),
8099            },
8100        ];
8101        c_full.contratos = vec![crate::aplicacao::WitContract {
8102            de: "demo-a".to_string(),
8103            para: "demo-b".to_string(),
8104            wit: "wasi:http/proxy".to_string(),
8105            endpoint: Some("/edge".to_string()),
8106            subject: None,
8107            slot: None,
8108        }];
8109        assert_eq!(membros_via_const_fn(&c_full), c_full.membros());
8110        assert_eq!(contratos_via_const_fn(&c_full), c_full.contratos());
8111        assert_eq!(membros_via_const_fn(&c_full).len(), 2);
8112        assert_eq!(contratos_via_const_fn(&c_full).len(), 1);
8113        // Alias-borrow check on the four remaining composite-carrier
8114        // slice-return arms — the wrapper's return borrow must alias the
8115        // caller's borrow so any future accessor re-routing that skips
8116        // the storage field surfaces through the assertion.
8117        assert!(std::ptr::eq(deps_via_const_fn(&c_full), c_full.deps()));
8118        assert!(std::ptr::eq(
8119            deps_dev_via_const_fn(&c_full),
8120            c_full.deps_dev()
8121        ));
8122        assert!(std::ptr::eq(
8123            upgrade_from_via_const_fn(&c_full),
8124            c_full.upgrade_from()
8125        ));
8126        assert!(std::ptr::eq(
8127            children_via_const_fn(&c_full),
8128            c_full.children()
8129        ));
8130    }
8131
8132    #[test]
8133    fn caixa_outer_option_composite_reference_return_accessor_family_is_const_fn() {
8134        // Fail-before-pass-after pin on the six outer-[`Caixa`]
8135        // `Option<Composite> → Option<&Composite>` reference-return
8136        // accessors — [`Caixa::limits`] / [`Caixa::behavior`] on the M2
8137        // Servico-runtime typed-slot axis, [`Caixa::politicas`] /
8138        // [`Caixa::placement`] / [`Caixa::entrada`] on the M3 mesh-slot
8139        // axis, and [`Caixa::ci`] on the Acao-kind typed-CI-run axis.
8140        // Each body is a bare `self.<field>.as_ref()` dispatch through
8141        // [`Option::as_ref`] (const-stable since Rust 1.83, well within
8142        // the workspace MSRV of 1.89). Any future accidental downgrade
8143        // to non-`const` fails the corresponding `<name>_via_const_fn`
8144        // wrapper at caixa-core build time with E0015 (`cannot call
8145        // non-const method`), strictly stronger than a runtime `assert!`
8146        // and strictly stronger than a module-scope `const _: () =
8147        // assert!(…)` pin (which cannot be formed on a `&Caixa` fixture
8148        // because the type's `String` / `Vec` / `Option<Composite>`
8149        // carriers rule out `const`-context value construction; the
8150        // `const fn` wrapper is the load-bearing shape that side-steps
8151        // the destructor-in-const restriction on the value axis while
8152        // still pinning the `const`-fn posture on the callee — mirror
8153        // of the sibling
8154        // [`caixa_outer_copy_return_accessor_pair_is_const_fn`] +
8155        // [`caixa_outer_string_slice_return_accessor_family_is_const_fn`] +
8156        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
8157        // pins' discipline verbatim on the peer outer-`Caixa` axes at
8158        // the same struct).
8159        //
8160        // Closes the outer-`Caixa` `Option<&Composite>` composite-
8161        // reference-return sub-family — the last unlifted altitude on
8162        // the outer-`Caixa` accessor-family const-eval surface after
8163        // the sibling `Copy`-return / universal-axis-`&str` /
8164        // `Option<&str>` / `&[String]` / composite-`&[T]` pins already
8165        // closed the sibling arms at 866d1d5 / 29c5d7e / 0650f64 /
8166        // 231a968 (the last of these pins the `Vec<T> → &[T]`
8167        // composite-slice arm the six accessors here close as their
8168        // `Option<Composite> → Option<&Composite>` peer). Peer of the
8169        // sibling inner-altitude nested-spec composite-reference-return
8170        // pin family — [`crate::AplicacaoSpec::politicas`] /
8171        // [`crate::AplicacaoSpec::placement`] /
8172        // [`crate::AplicacaoSpec::entrada`] on the inner
8173        // [`crate::AplicacaoSpec`] altitude (already `pub const fn`
8174        // per 0b23e0f), and the outer-`Caixa` altitude here now carries
8175        // the same shape so both altitudes of the reference-return
8176        // discipline (per-`Caixa` outer-slot presence + per-
8177        // `AplicacaoSpec` inner-slot presence) route through one typed
8178        // const dispatch on the substrate primitive.
8179        const fn limits_via_const_fn(c: &Caixa) -> Option<&LimitsSpec> {
8180            c.limits()
8181        }
8182        const fn behavior_via_const_fn(c: &Caixa) -> Option<&crate::BehaviorSpec> {
8183            c.behavior()
8184        }
8185        const fn politicas_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::MeshPolicy> {
8186            c.politicas()
8187        }
8188        const fn placement_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Placement> {
8189            c.placement()
8190        }
8191        const fn entrada_via_const_fn(c: &Caixa) -> Option<&crate::aplicacao::Entrada> {
8192            c.entrada()
8193        }
8194        const fn ci_via_const_fn(c: &Caixa) -> Option<&canteiro_types::CiRun> {
8195            c.ci()
8196        }
8197        // Both-arm sweep on every accessor: the `None` author-omitted
8198        // arm (template default — no M2/M3/CI slot declared) and the
8199        // `Some(<composite>)` authored arm (mutated below via struct-
8200        // literal seeds, side-stepping the parser-side `:kind`-gated
8201        // cross-slot invariants irrelevant to the accessor dispatch
8202        // under test). Both arms route through the `const fn` wrapper
8203        // family so the two-arm `Option` partition is pinned through
8204        // the same const dispatch as the runtime path.
8205        let c_empty = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8206        assert!(limits_via_const_fn(&c_empty).is_none());
8207        assert!(behavior_via_const_fn(&c_empty).is_none());
8208        assert!(politicas_via_const_fn(&c_empty).is_none());
8209        assert!(placement_via_const_fn(&c_empty).is_none());
8210        assert!(entrada_via_const_fn(&c_empty).is_none());
8211        assert!(ci_via_const_fn(&c_empty).is_none());
8212        let mut c_full = Caixa::from_lisp(&Caixa::template("demo")).expect("template must parse");
8213        c_full.limits = Some(LimitsSpec::default());
8214        c_full.behavior = Some(crate::BehaviorSpec::default());
8215        c_full.politicas = Some(crate::aplicacao::MeshPolicy::default());
8216        c_full.placement = Some(crate::aplicacao::Placement::default());
8217        c_full.entrada = Some(crate::aplicacao::Entrada {
8218            host: "demo.quero.cloud".to_string(),
8219            para: "demo".to_string(),
8220            paths: Vec::new(),
8221            port: crate::aplicacao::DEFAULT_SERVICO_PORT,
8222        });
8223        c_full.ci = Some(canteiro_types::CiRun {
8224            workspace: "pleme-io".into(),
8225            repo: "caixa".into(),
8226            nodes: vec![],
8227        });
8228        assert!(limits_via_const_fn(&c_full).is_some());
8229        assert!(behavior_via_const_fn(&c_full).is_some());
8230        assert!(politicas_via_const_fn(&c_full).is_some());
8231        assert!(placement_via_const_fn(&c_full).is_some());
8232        assert!(entrada_via_const_fn(&c_full).is_some());
8233        assert!(ci_via_const_fn(&c_full).is_some());
8234        // Alias-borrow check on every arm: the wrapper's inner-`Option`
8235        // reference must alias the caller's borrow so any future accessor
8236        // re-routing that skips the storage field surfaces through the
8237        // assertion.
8238        assert!(std::ptr::eq(
8239            limits_via_const_fn(&c_full).unwrap(),
8240            c_full.limits().unwrap()
8241        ));
8242        assert!(std::ptr::eq(
8243            behavior_via_const_fn(&c_full).unwrap(),
8244            c_full.behavior().unwrap()
8245        ));
8246        assert!(std::ptr::eq(
8247            politicas_via_const_fn(&c_full).unwrap(),
8248            c_full.politicas().unwrap()
8249        ));
8250        assert!(std::ptr::eq(
8251            placement_via_const_fn(&c_full).unwrap(),
8252            c_full.placement().unwrap()
8253        ));
8254        assert!(std::ptr::eq(
8255            entrada_via_const_fn(&c_full).unwrap(),
8256            c_full.entrada().unwrap()
8257        ));
8258        assert!(std::ptr::eq(
8259            ci_via_const_fn(&c_full).unwrap(),
8260            c_full.ci().unwrap()
8261        ));
8262    }
8263
8264    #[test]
8265    fn register_populates_registry() {
8266        Caixa::register().expect("first register call in this test process must succeed");
8267        let kws = tatara_lisp::domain::registered_keywords();
8268        assert!(kws.contains(&"defcaixa"));
8269    }
8270
8271    #[test]
8272    fn to_lisp_round_trips() {
8273        let src = Caixa::template("demo");
8274        let c1 = Caixa::from_lisp(&src).unwrap();
8275        let emitted = c1.to_lisp();
8276        let c2 = Caixa::from_lisp(&emitted).expect("emitted lisp parses back");
8277        assert_eq!(c1, c2);
8278    }
8279
8280    // ── DialetoEstrangeiro carries a single typed axis ────────────────────
8281    //
8282    // The compounding pin: the variant stores only the typed
8283    // [`crate::dialeto::CaixaDialeto`], and every user-facing byte-string
8284    // (canonical keyword, description, consumer) routes through the enum's
8285    // own accessors at Display time. Prior to that closure the variant
8286    // carried each accessor's return value as a stored `&'static str`
8287    // snapshot alongside `dialeto`; a caller could construct the variant
8288    // with a snapshot that drifted from what `dialeto`'s accessors would
8289    // return, and every downstream user-facing projection would silently
8290    // disagree with the classification. Storing only the axis makes the
8291    // drift structurally impossible.
8292
8293    #[test]
8294    fn dialeto_estrangeiro_variant_carries_only_the_typed_dialeto_axis() {
8295        // Single-field construction is the whole compounding shape — a
8296        // future re-introduction of a snapshot field (a `palavra_canonica:
8297        // &'static str`, a stored `descricao:`, a stored `consumidor:`)
8298        // would re-open the drift surface and this construction would fail
8299        // to compile with "missing field" until every snapshot was seeded
8300        // at the call site again. The compile-time guarantee is the
8301        // invariant; the assertion below only witnesses that the
8302        // construction is well-formed after the closure.
8303        let err = LeituraError::DialetoEstrangeiro {
8304            dialeto: crate::dialeto::CaixaDialeto::Molde,
8305        };
8306        assert!(matches!(
8307            err,
8308            LeituraError::DialetoEstrangeiro {
8309                dialeto: crate::dialeto::CaixaDialeto::Molde,
8310            }
8311        ));
8312    }
8313
8314    #[test]
8315    fn dialeto_estrangeiro_display_routes_through_typed_dialeto_accessors() {
8316        // For every foreign-dialect classification the variant surfaces —
8317        // [`crate::dialeto::CaixaDialeto::Molde`] and
8318        // [`crate::dialeto::CaixaDialeto::MoldePosicional`], the two
8319        // variants [`Caixa::from_lisp`] raises this error for — the
8320        // rendered [`std::fmt::Display`] byte-string must interpolate each
8321        // typed accessor's return verbatim. A future re-introduction of a
8322        // stored `&'static str` snapshot alongside `dialeto` that Display
8323        // read instead of the accessor would fail this pin as soon as the
8324        // two disagreed; a future accessor rebrand (a per-dialect
8325        // consumer rename, a canonical-keyword shift once the substrate
8326        // migration named in [`crate::dialeto`] completes) reaches every
8327        // consumer through one typed dispatch and this pin verifies the
8328        // display path is one of them.
8329        for d in [
8330            crate::dialeto::CaixaDialeto::Molde,
8331            crate::dialeto::CaixaDialeto::MoldePosicional,
8332        ] {
8333            let rendered = LeituraError::DialetoEstrangeiro { dialeto: d }.to_string();
8334            assert!(
8335                rendered.contains(d.palavra_canonica()),
8336                "Display must interpolate `dialeto.palavra_canonica()` \
8337                 verbatim — a stored snapshot would silently drift from \
8338                 the typed accessor. dialect: {d}, rendered: {rendered:?}"
8339            );
8340            assert!(
8341                rendered.contains(d.descricao()),
8342                "Display must interpolate `dialeto.descricao()` verbatim. \
8343                 dialect: {d}, rendered: {rendered:?}"
8344            );
8345            assert!(
8346                rendered.contains(d.consumidor()),
8347                "Display must interpolate `dialeto.consumidor()` verbatim. \
8348                 dialect: {d}, rendered: {rendered:?}"
8349            );
8350        }
8351    }
8352
8353    #[test]
8354    fn from_lisp_rejects_molde_dialect_via_typed_variant() {
8355        // The end-to-end pin the compounding closure defends: a
8356        // Molde-dialect source lands as [`LeituraError::DialetoEstrangeiro`]
8357        // carrying [`crate::dialeto::CaixaDialeto::Molde`], and the
8358        // rendered Display byte-string names the Molde accessors'
8359        // returns verbatim. Any future path that constructed the variant
8360        // with a mismatched snapshot (a stored `palavra_canonica:
8361        // "defcaixa"` on a `Molde` classification) would land Display
8362        // pointing at `defcaixa` while the typed axis said `Molde` — the
8363        // exact drift the closure removes.
8364        let src = r#"
8365          (defcaixa
8366            :name "x"
8367            :kind :Biblioteca
8368            :ecosystem :rust-single-crate
8369            :package {:name "x" :version "0.1.0"})
8370        "#;
8371        let err = Caixa::from_lisp(src).expect_err("Molde dialect must not parse as Pacote");
8372        match err {
8373            LeituraError::DialetoEstrangeiro { dialeto } => {
8374                assert_eq!(dialeto, crate::dialeto::CaixaDialeto::Molde);
8375                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
8376                assert!(rendered.contains(dialeto.palavra_canonica()));
8377                assert!(rendered.contains(dialeto.consumidor()));
8378                assert!(rendered.contains(dialeto.descricao()));
8379            }
8380            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
8381        }
8382    }
8383
8384    #[test]
8385    fn from_lisp_rejects_molde_posicional_dialect_via_typed_variant() {
8386        // Coverage pin for the [`crate::dialeto::CaixaDialeto::MoldePosicional`]
8387        // arm of the [`Caixa::from_lisp`] foreign-dialect gate — the
8388        // positional-arity `defmolde` form written under a `(defcaixa …)`
8389        // head (`(defcaixa todoku-go :kind :Biblioteca :ecosystem :go
8390        // …)`). Pre-lift this arm rode the same `foreign =>` wildcard
8391        // the [`crate::dialeto::CaixaDialeto::Molde`] sibling arm rode,
8392        // so no test exercised the positional-arity path through
8393        // `Caixa::from_lisp` specifically; the sibling
8394        // [`from_lisp_rejects_molde_dialect_via_typed_variant`] only
8395        // covered [`crate::dialeto::CaixaDialeto::Molde`]. Post-lift the
8396        // two arms route through the lifted
8397        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
8398        // typed predicate — the same predicate the pre-lift `foreign =>`
8399        // wildcard resolved to today — and this pin makes the
8400        // positional-arity arm's byte-shape at the gate explicit rather
8401        // than implied by wildcard-absorption. A future regression that
8402        // silently reordered [`crate::dialeto::CaixaDialeto::is_molde_family`]'s
8403        // arm-set (dropped [`crate::dialeto::CaixaDialeto::MoldePosicional`]
8404        // from the two-arity closure) would fail this pin at caixa-core
8405        // test time rather than surfacing far from the change as a
8406        // `caixa.lisp` carrying a `(defcaixa todoku-go :ecosystem :go
8407        // …)` silently parsing past the derive.
8408        let src = r#"
8409          (defcaixa todoku-go
8410            :kind :Biblioteca
8411            :ecosystem :go
8412            :package {:name "todoku-go" :version "0.3.0"})
8413        "#;
8414        let err =
8415            Caixa::from_lisp(src).expect_err("MoldePosicional dialect must not parse as Pacote");
8416        match err {
8417            LeituraError::DialetoEstrangeiro { dialeto } => {
8418                assert_eq!(
8419                    dialeto,
8420                    crate::dialeto::CaixaDialeto::MoldePosicional,
8421                    "DialetoEstrangeiro must carry the MoldePosicional \
8422                     variant verbatim — the positional-arity `defmolde` \
8423                     form under a `(defcaixa …)` head is the \
8424                     `MoldePosicional` arm's canonical byte-shape"
8425                );
8426                let rendered = LeituraError::DialetoEstrangeiro { dialeto }.to_string();
8427                assert!(
8428                    rendered.contains(dialeto.palavra_canonica()),
8429                    "Display must interpolate `dialeto.palavra_canonica()` \
8430                     verbatim on the MoldePosicional arm; rendered: \
8431                     {rendered:?}"
8432                );
8433                assert!(
8434                    rendered.contains(dialeto.consumidor()),
8435                    "Display must interpolate `dialeto.consumidor()` \
8436                     verbatim on the MoldePosicional arm; rendered: \
8437                     {rendered:?}"
8438                );
8439                assert!(
8440                    rendered.contains(dialeto.descricao()),
8441                    "Display must interpolate `dialeto.descricao()` \
8442                     verbatim on the MoldePosicional arm; rendered: \
8443                     {rendered:?}"
8444                );
8445            }
8446            other => panic!("expected DialetoEstrangeiro, got {other:?}"),
8447        }
8448    }
8449
8450    #[test]
8451    fn from_lisp_dialect_gate_dispatches_through_caixa_dialeto_is_molde_family_predicate() {
8452        // Load-bearing byte-parity pin: for every arm in
8453        // [`crate::dialeto::CaixaDialeto::ALL`], the
8454        // [`Caixa::from_lisp`] foreign-dialect gate's DialetoEstrangeiro
8455        // partition must agree with the lifted
8456        // [`crate::dialeto::CaixaDialeto::is_molde_family`] (e9d2315)
8457        // typed predicate — i.e. from_lisp raises
8458        // [`LeituraError::DialetoEstrangeiro`] carrying `d` iff
8459        // `d.is_molde_family()` returns `true`, and does NOT raise
8460        // [`LeituraError::DialetoEstrangeiro`] on any arm where the
8461        // predicate returns `false` (the arm's source falls through to
8462        // the derive — parses cleanly on
8463        // [`crate::dialeto::CaixaDialeto::Pacote`], surfaces a
8464        // [`LeituraError::Leitura`] on
8465        // [`crate::dialeto::CaixaDialeto::Desconhecido`]).
8466        //
8467        // Pre-lift the gate hand-rolled a three-arm match
8468        // (`Pacote => {}`, `Desconhecido => {}`, `foreign => Err(…)`)
8469        // whose `foreign =>` wildcard expressed no compile-time link
8470        // back to the substrate primitive's arm-family; a future fifth
8471        // dialect the [`crate::dialeto`] module doc's "third dialect"
8472        // hazard actualises would fall silently onto the wildcard
8473        // regardless of whether it belonged to the `defmolde` family or
8474        // to a distinct `defcaixa`-family. Post-lift the partition
8475        // resolves through
8476        // [`crate::dialeto::CaixaDialeto::is_molde_family`]'s single
8477        // typed dispatch, and this pin refuses any future regression
8478        // that silently split the from_lisp partition from the typed
8479        // predicate — the two paths now migrate as one on any future
8480        // arm addition.
8481        //
8482        // Sibling in shape to the peer
8483        // [`crate::dialeto::tests::caixa_dialeto_is_molde_family_agrees_with_palavra_canonica_defmolde_projection`]
8484        // (e9d2315) that pins the same byte-parity between
8485        // [`crate::dialeto::CaixaDialeto::is_molde_family`] and the
8486        // sibling [`crate::dialeto::CaixaDialeto::palavra_canonica`]
8487        // `== "defmolde"` classifier — extends the discipline from the
8488        // two paths within the [`crate::dialeto`] primitive onto the
8489        // third external consumer of the `defmolde`-family partition
8490        // (the [`Caixa::from_lisp`] gate that raises
8491        // [`LeituraError::DialetoEstrangeiro`]).
8492        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
8493            (
8494                crate::dialeto::CaixaDialeto::Pacote,
8495                r#"
8496                  (defcaixa
8497                    :nome   "checkout"
8498                    :versao "0.1.0"
8499                    :kind   Biblioteca
8500                    :edicao "2026"
8501                    :descricao "canonical Pacote source"
8502                    :autores ()
8503                    :etiquetas ()
8504                    :deps ()
8505                    :deps-dev ()
8506                    :bibliotecas ("lib/checkout.lisp"))
8507                "#,
8508            ),
8509            (
8510                crate::dialeto::CaixaDialeto::Molde,
8511                r#"
8512                  (defcaixa
8513                    :name "base64"
8514                    :kind :Biblioteca
8515                    :ecosystem :rust-single-crate
8516                    :package {:name "base64" :version "0.22.1"}
8517                    :workflows [:auto-release])
8518                "#,
8519            ),
8520            (
8521                crate::dialeto::CaixaDialeto::MoldePosicional,
8522                r#"
8523                  (defcaixa todoku-go
8524                    :kind :Biblioteca
8525                    :ecosystem :go
8526                    :package {:name "todoku-go" :version "0.3.0"})
8527                "#,
8528            ),
8529            (
8530                crate::dialeto::CaixaDialeto::Desconhecido,
8531                r#"(defcaixa :licenca "MIT")"#,
8532            ),
8533        ];
8534
8535        // Coverage: every arm in [`crate::dialeto::CaixaDialeto::ALL`]
8536        // must appear in the fixture table so the pin's arm-set stays
8537        // synchronised with the enum's arm-set. Fails at test time if a
8538        // future fifth arm added to [`crate::dialeto::CaixaDialeto`]
8539        // (with a corresponding `is_molde_family` return) forgot to
8540        // extend this fixture table with a canonical source for the new
8541        // arm — the pin cannot cover an arm it has no source for.
8542        for &expected in crate::dialeto::CaixaDialeto::ALL {
8543            assert!(
8544                fixtures.iter().any(|(d, _)| *d == expected),
8545                "fixture table must carry a canonical source for every \
8546                 CaixaDialeto arm; missing: {expected:?}"
8547            );
8548        }
8549
8550        for &(expected_dialect, src) in fixtures {
8551            let classified = crate::dialeto::classify(src.trim()).unwrap_or_else(|err| {
8552                panic!(
8553                    "fixture source for {expected_dialect:?} must classify \
8554                     cleanly, got err: {err:?}"
8555                )
8556            });
8557            assert_eq!(
8558                classified, expected_dialect,
8559                "fixture source for {expected_dialect:?} must classify as \
8560                 {expected_dialect:?} (drift here defeats the byte-parity \
8561                 pin below — a source labelled for one arm but classifying \
8562                 as another would silently satisfy or violate the pin for \
8563                 the wrong reason)"
8564            );
8565
8566            let outcome = Caixa::from_lisp(src);
8567            match (expected_dialect.is_molde_family(), &outcome) {
8568                (true, Err(LeituraError::DialetoEstrangeiro { dialeto })) => {
8569                    assert_eq!(
8570                        *dialeto, expected_dialect,
8571                        "DialetoEstrangeiro must carry the same typed arm \
8572                         the classifier returned — a drift here would let \
8573                         from_lisp raise the error while pointing at the \
8574                         wrong dialect (e.g. rejecting a \
8575                         MoldePosicional source as Molde). arm: \
8576                         {expected_dialect:?}"
8577                    );
8578                }
8579                (true, other) => panic!(
8580                    "arm {expected_dialect:?} has is_molde_family() = true \
8581                     so from_lisp must raise DialetoEstrangeiro carrying \
8582                     {expected_dialect:?}; got: {other:?}"
8583                ),
8584                (false, Err(LeituraError::DialetoEstrangeiro { dialeto })) => panic!(
8585                    "arm {expected_dialect:?} has is_molde_family() = false \
8586                     so from_lisp must NOT raise DialetoEstrangeiro; got \
8587                     one carrying: {dialeto:?}. This means the typed \
8588                     predicate and the from_lisp partition disagree on \
8589                     this arm — exactly the drift this pin refuses."
8590                ),
8591                (false, _) => {
8592                    // A non-molde arm's source falls through to the
8593                    // derive: Pacote sources parse to Ok(_); Desconhecido
8594                    // sources surface as LeituraError::Leitura from the
8595                    // derive's own unknown-keyword rejection. Either
8596                    // shape is acceptable here — the pin's promise is
8597                    // narrower: "no DialetoEstrangeiro on
8598                    // is_molde_family() == false".
8599                }
8600            }
8601        }
8602    }
8603
8604    // ── M2 typed-substrate slot tests (limits, behavior, upgrade-from, supervisor) ──
8605
8606    #[test]
8607    fn limits_round_trip_via_json() {
8608        use crate::LimitsSpec;
8609        use std::time::Duration;
8610        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8611        c.limits = Some(LimitsSpec {
8612            memory: Some(64 * 1024 * 1024),
8613            fuel: Some(1_000_000),
8614            wall_clock: Some(Duration::from_secs(30)),
8615            cpu: Some(500),
8616        });
8617        let json = serde_json::to_string(&c).unwrap();
8618        assert!(json.contains("\"limits\""));
8619        assert!(json.contains("\"64MiB\""));
8620        assert!(json.contains("\"30s\""));
8621        assert!(json.contains("\"500m\""));
8622        let back: Caixa = serde_json::from_str(&json).unwrap();
8623        assert_eq!(c.limits, back.limits);
8624    }
8625
8626    #[test]
8627    fn behavior_round_trip_via_json() {
8628        use crate::BehaviorSpec;
8629        use std::path::PathBuf;
8630        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8631        c.behavior = Some(BehaviorSpec {
8632            on_init: Some(PathBuf::from("lib/init.lisp")),
8633            on_call: Some(PathBuf::from("lib/handlers.lisp")),
8634            ..Default::default()
8635        });
8636        let json = serde_json::to_string(&c).unwrap();
8637        let back: Caixa = serde_json::from_str(&json).unwrap();
8638        assert_eq!(c.behavior, back.behavior);
8639    }
8640
8641    #[test]
8642    fn upgrade_from_round_trip_via_json() {
8643        use crate::{UpgradeFromEntry, UpgradeInstruction};
8644        use std::path::PathBuf;
8645        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8646        c.upgrade_from = vec![UpgradeFromEntry {
8647            from: "0.1.0".into(),
8648            instructions: vec![
8649                UpgradeInstruction::LoadModule {
8650                    module: "demo".into(),
8651                },
8652                UpgradeInstruction::StateChange {
8653                    script: PathBuf::from("lib/migrations/v01-to-v02.lisp"),
8654                },
8655                UpgradeInstruction::SoftPurge {
8656                    module: "demo-old".into(),
8657                },
8658            ],
8659        }];
8660        let json = serde_json::to_string(&c).unwrap();
8661        let back: Caixa = serde_json::from_str(&json).unwrap();
8662        assert_eq!(c.upgrade_from, back.upgrade_from);
8663    }
8664
8665    #[test]
8666    fn supervisor_view_returns_typed_shape() {
8667        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
8668        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
8669        c.kind = CaixaKind::Supervisor;
8670        c.bibliotecas.clear();
8671        c.estrategia = Some(RestartStrategy::OneForOne);
8672        c.max_restarts = Some(5);
8673        c.restart_window = Some("60s".into());
8674        c.children = vec![ChildSpec {
8675            caixa: "worker".into(),
8676            versao: "^0.1".into(),
8677            restart: RestartPolicy::Permanent,
8678        }];
8679        let view = c.supervisor_view().expect("Supervisor kind has a view");
8680        assert_eq!(view.estrategia, RestartStrategy::OneForOne);
8681        assert_eq!(view.max_restarts, 5);
8682        assert_eq!(
8683            view.restart_window,
8684            Some(std::time::Duration::from_secs(60))
8685        );
8686        assert_eq!(view.children.len(), 1);
8687        view.validate().unwrap();
8688    }
8689
8690    #[test]
8691    fn supervisor_view_none_for_non_supervisor_kinds() {
8692        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8693        assert!(c.supervisor_view().is_none());
8694    }
8695
8696    #[test]
8697    fn declared_mesh_slots_empty_for_bare_caixa() {
8698        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8699        assert!(c.declared_mesh_slots().is_empty());
8700    }
8701
8702    #[test]
8703    fn declared_mesh_slots_reports_only_set_slots_in_canonical_order() {
8704        use crate::{Entrada, Membro};
8705        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8706        // Set a non-adjacent pair (:membros + :entrada) to pin that the
8707        // canonical declaration order is preserved regardless of which
8708        // subset is populated.
8709        c.membros = vec![Membro {
8710            caixa: "a".into(),
8711            versao: "^0.1".into(),
8712        }];
8713        c.entrada = Some(Entrada {
8714            host: "x.example.com".into(),
8715            para: "a".into(),
8716            paths: vec![],
8717            port: 8080,
8718        });
8719        assert_eq!(
8720            c.declared_mesh_slots(),
8721            vec![
8722                crate::render::M3_AUTHOR_KEY_MEMBROS,
8723                crate::render::M3_AUTHOR_KEY_ENTRADA,
8724            ]
8725        );
8726    }
8727
8728    #[test]
8729    fn m3_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8730        // Scalar-value pin: the five author-facing kebab-case labels the
8731        // `(defcaixa … :<slot> (…))` surface admits on the M3 top-level
8732        // mesh slot axis, one arm per typed slot. Mirrors the peer
8733        // scalar-value pin the sibling
8734        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
8735        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
8736        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] M2 top-level slot consts
8737        // carry (f49c8b0), so both altitudes of the typed-slot algebra
8738        // (per-Servico M2 + per-Aplicacao M3) share the same
8739        // "one canonical byte-string per arm" discipline. A future
8740        // rebrand (`:membros` → `:members`, `:contratos` → `:contracts`,
8741        // `:politicas` → `:policies`, `:placement` → `:distribution`,
8742        // `:entrada` → `:ingress`) lands as an edit to exactly one const,
8743        // and every consumer that reaches for the label picks it up at
8744        // build time rather than at runtime as a downstream mismatch.
8745        assert_eq!(crate::render::M3_AUTHOR_KEY_MEMBROS, ":membros");
8746        assert_eq!(crate::render::M3_AUTHOR_KEY_CONTRATOS, ":contratos");
8747        assert_eq!(crate::render::M3_AUTHOR_KEY_POLITICAS, ":politicas");
8748        assert_eq!(crate::render::M3_AUTHOR_KEY_PLACEMENT, ":placement");
8749        assert_eq!(crate::render::M3_AUTHOR_KEY_ENTRADA, ":entrada");
8750    }
8751
8752    #[test]
8753    fn declared_mesh_slots_route_through_lifted_m3_author_key_consts() {
8754        // Production-through-const pin: the five per-arm labels the
8755        // [`Caixa::declared_mesh_slots`] tagger pushes onto its return
8756        // `Vec` route through the lifted
8757        // [`crate::M3_AUTHOR_KEY_MEMBROS`] /
8758        // [`crate::M3_AUTHOR_KEY_CONTRATOS`] /
8759        // [`crate::M3_AUTHOR_KEY_POLITICAS`] /
8760        // [`crate::M3_AUTHOR_KEY_PLACEMENT`] /
8761        // [`crate::M3_AUTHOR_KEY_ENTRADA`] consts, in canonical
8762        // declaration order. A future re-order or drift at the tagger
8763        // (a rename that reaches the tagger but not the const, or vice
8764        // versa) surfaces here at build time rather than at runtime as
8765        // a [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
8766        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8767        // commit. Mirror of the peer
8768        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
8769        // pin (f49c8b0) on the sibling per-Servico M2 top-level slot
8770        // axis.
8771        use crate::{Entrada, Membro, MeshPolicy, Placement, PlacementStrategy, WitContract};
8772        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8773        c.membros = vec![Membro {
8774            caixa: "a".into(),
8775            versao: "^0.1".into(),
8776        }];
8777        c.contratos = vec![WitContract {
8778            de: "a".into(),
8779            para: "a".into(),
8780            wit: "wasi:http/proxy".into(),
8781            endpoint: Some("/x".into()),
8782            subject: None,
8783            slot: None,
8784        }];
8785        c.politicas = Some(MeshPolicy::default());
8786        c.placement = Some(Placement {
8787            estrategia: PlacementStrategy::Replicated,
8788            clusters: vec!["rio".into()],
8789            affinity: None,
8790            shard_key: None,
8791        });
8792        c.entrada = Some(Entrada {
8793            host: "x.example.com".into(),
8794            para: "a".into(),
8795            paths: vec![],
8796            port: 8080,
8797        });
8798        assert_eq!(
8799            c.declared_mesh_slots(),
8800            vec![
8801                crate::render::M3_AUTHOR_KEY_MEMBROS,
8802                crate::render::M3_AUTHOR_KEY_CONTRATOS,
8803                crate::render::M3_AUTHOR_KEY_POLITICAS,
8804                crate::render::M3_AUTHOR_KEY_PLACEMENT,
8805                crate::render::M3_AUTHOR_KEY_ENTRADA,
8806            ]
8807        );
8808    }
8809
8810    #[test]
8811    fn declared_supervisor_slots_empty_for_bare_caixa() {
8812        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8813        assert!(c.declared_supervisor_slots().is_empty());
8814    }
8815
8816    #[test]
8817    fn declared_supervisor_slots_reports_only_set_slots_in_canonical_order() {
8818        use crate::RestartStrategy;
8819        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8820        // Set a non-adjacent pair (:estrategia + :restart-window) to pin
8821        // that the canonical declaration order is preserved regardless
8822        // of which subset is populated.
8823        c.estrategia = Some(RestartStrategy::OneForOne);
8824        c.restart_window = Some("60s".into());
8825        assert_eq!(
8826            c.declared_supervisor_slots(),
8827            vec![
8828                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8829                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8830            ]
8831        );
8832    }
8833
8834    #[test]
8835    fn supervisor_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8836        // Scalar-value pin: the four author-facing kebab-case labels the
8837        // `(defcaixa … :<slot> (…))` surface admits on the Supervisor
8838        // supervision-tree slot axis, one arm per typed slot. Mirrors the
8839        // peer scalar-value pins the sibling
8840        // [`crate::render::M2_AUTHOR_KEY_LIMITS`] /
8841        // [`crate::render::M2_AUTHOR_KEY_BEHAVIOR`] /
8842        // [`crate::render::M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot
8843        // consts and [`crate::render::M3_AUTHOR_KEY_MEMBROS`] etc.
8844        // top-level M3 slot consts carry, so all three kind-scoped
8845        // typed-slot-family author-facing-label axes route through one
8846        // canonical per-arm declaration. A future rebrand
8847        // (`:estrategia` → `:strategy` for English uniformity,
8848        // `:max-restarts` → `:max-intensity` matching Erlang/OTP's
8849        // `MaxIntensity` name, `:restart-window` → `:period` matching
8850        // OTP's `Period` name, `:children` → `:workers` matching Elixir
8851        // idiom) lands as an edit to exactly one const, and every
8852        // consumer that reaches for the label picks it up at build time
8853        // rather than at runtime as a downstream mismatch.
8854        assert_eq!(
8855            crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8856            ":estrategia"
8857        );
8858        assert_eq!(
8859            crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
8860            ":max-restarts"
8861        );
8862        assert_eq!(
8863            crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8864            ":restart-window"
8865        );
8866        assert_eq!(crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN, ":children");
8867    }
8868
8869    #[test]
8870    fn declared_supervisor_slots_route_through_lifted_supervisor_author_key_consts() {
8871        // Production-through-const pin: the four per-arm labels the
8872        // [`Caixa::declared_supervisor_slots`] tagger pushes onto its
8873        // return `Vec` route through the lifted
8874        // [`crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] /
8875        // [`crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS`] /
8876        // [`crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW`] /
8877        // [`crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN`] consts, in
8878        // canonical declaration order. A future re-order or drift at the
8879        // tagger (a rename that reaches the tagger but not the const, or
8880        // vice versa) surfaces here at build time rather than at runtime
8881        // as a [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
8882        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8883        // commit. Mirror of the peer
8884        // [`declared_servico_slots_route_through_lifted_m2_author_key_consts`]
8885        // (f49c8b0) and
8886        // [`declared_mesh_slots_route_through_lifted_m3_author_key_consts`]
8887        // (882f498) pins on the sibling M2 / M3 top-level slot axes.
8888        use crate::{ChildSpec, RestartPolicy, RestartStrategy};
8889        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8890        c.estrategia = Some(RestartStrategy::OneForOne);
8891        c.max_restarts = Some(5);
8892        c.restart_window = Some("60s".into());
8893        c.children = vec![ChildSpec {
8894            caixa: "worker".into(),
8895            versao: "^0.1".into(),
8896            restart: RestartPolicy::Permanent,
8897        }];
8898        assert_eq!(
8899            c.declared_supervisor_slots(),
8900            vec![
8901                crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA,
8902                crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS,
8903                crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW,
8904                crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN,
8905            ]
8906        );
8907    }
8908
8909    #[test]
8910    fn declared_servico_slots_empty_for_bare_caixa() {
8911        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8912        assert!(c.declared_servico_slots().is_empty());
8913    }
8914
8915    #[test]
8916    fn declared_servico_slots_reports_only_set_slots_in_canonical_order() {
8917        use crate::{UpgradeFromEntry, UpgradeInstruction};
8918        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8919        // Set a non-adjacent pair (:limits + :upgrade-from) to pin that
8920        // the canonical declaration order is preserved regardless of
8921        // which subset is populated.
8922        c.limits = Some(crate::LimitsSpec {
8923            fuel: Some(1_000_000),
8924            ..Default::default()
8925        });
8926        c.upgrade_from = vec![UpgradeFromEntry {
8927            from: "0.1.0".into(),
8928            instructions: vec![UpgradeInstruction::Restart],
8929        }];
8930        assert_eq!(
8931            c.declared_servico_slots(),
8932            vec![
8933                crate::render::M2_AUTHOR_KEY_LIMITS,
8934                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
8935            ]
8936        );
8937    }
8938
8939    #[test]
8940    fn m2_top_level_author_key_consts_pin_canonical_kebab_case_labels() {
8941        // Scalar-value pin: the three author-facing kebab-case labels
8942        // the `(defcaixa … :<slot> (…))` surface admits on the M2
8943        // top-level slot axis, one arm per typed slot. Mirrors the peer
8944        // scalar-value pin the sibling renderer-side
8945        // [`crate::M2_KEY_LIMITS`] / [`crate::M2_KEY_BEHAVIOR`] /
8946        // [`crate::M2_KEY_UPGRADE_FROM`] camelCase overlay-container
8947        // consts carry, so both halves of the M2 top-level slot dual
8948        // axis (author-facing kebab-case label + renderer-side
8949        // camelCase overlay-container wire key) route through one
8950        // canonical per-arm declaration. A future rebrand
8951        // (`:limits` → `:sandbox` matching Lunatic per-process
8952        // terminology INSPIRATIONS §III.1, `:behavior` → `:gen-server`
8953        // matching Erlang's verbatim name, `:upgrade-from` → `:appup`
8954        // matching Erlang's verbatim appup name) lands as an edit to
8955        // exactly one const, and every consumer that reaches for the
8956        // label picks it up at build time rather than at runtime as a
8957        // downstream mismatch.
8958        assert_eq!(crate::render::M2_AUTHOR_KEY_LIMITS, ":limits");
8959        assert_eq!(crate::render::M2_AUTHOR_KEY_BEHAVIOR, ":behavior");
8960        assert_eq!(crate::render::M2_AUTHOR_KEY_UPGRADE_FROM, ":upgrade-from");
8961    }
8962
8963    #[test]
8964    fn declared_servico_slots_route_through_lifted_m2_author_key_consts() {
8965        // Production-through-const pin: the three per-arm labels the
8966        // [`Caixa::declared_servico_slots`] tagger pushes onto its
8967        // return `Vec` route through the lifted
8968        // [`crate::M2_AUTHOR_KEY_LIMITS`] /
8969        // [`crate::M2_AUTHOR_KEY_BEHAVIOR`] /
8970        // [`crate::M2_AUTHOR_KEY_UPGRADE_FROM`] consts, in canonical
8971        // declaration order. A future re-order or drift at the tagger
8972        // (a rename that reaches the tagger but not the const, or vice
8973        // versa) surfaces here at build time rather than at runtime as
8974        // a [`crate::LayoutError::ServicoSlotsOnNonServico`]
8975        // `slots: <stale-kebab-case>` diagnostic far from the rename's
8976        // commit. Mirror of the peer
8977        // [`crate::behavior::BehaviorSpec::declared_slots`] production
8978        // tagger pin (889dc18) on the sibling per-callback axis.
8979        use crate::{BehaviorSpec, UpgradeFromEntry, UpgradeInstruction};
8980        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
8981        c.limits = Some(crate::LimitsSpec {
8982            fuel: Some(1_000_000),
8983            ..Default::default()
8984        });
8985        c.behavior = Some(BehaviorSpec {
8986            on_init: Some(PathBuf::from("lib/init.lisp")),
8987            ..Default::default()
8988        });
8989        c.upgrade_from = vec![UpgradeFromEntry {
8990            from: "0.1.0".into(),
8991            instructions: vec![UpgradeInstruction::Restart],
8992        }];
8993        assert_eq!(
8994            c.declared_servico_slots(),
8995            vec![
8996                crate::render::M2_AUTHOR_KEY_LIMITS,
8997                crate::render::M2_AUTHOR_KEY_BEHAVIOR,
8998                crate::render::M2_AUTHOR_KEY_UPGRADE_FROM,
8999            ]
9000        );
9001    }
9002
9003    #[test]
9004    fn existing_manifests_unaffected_by_new_optional_slots() {
9005        // Regression test: a caixa.lisp authored before M2 typed slots
9006        // should still parse + serialize cleanly. The bare `defcaixa`
9007        // emitted by `Caixa::template` has none of the new fields.
9008        let src = Caixa::template("legacy");
9009        let c = Caixa::from_lisp(&src).unwrap();
9010        assert!(c.limits.is_none());
9011        assert!(c.behavior.is_none());
9012        assert!(c.upgrade_from.is_empty());
9013        assert!(c.estrategia.is_none());
9014        assert!(c.children.is_empty());
9015
9016        // And to_lisp emits a manifest with the new slots in the
9017        // empty/default state — round-trippable.
9018        let emitted = c.to_lisp();
9019        let back = Caixa::from_lisp(&emitted).unwrap();
9020        assert_eq!(c, back);
9021    }
9022
9023    #[test]
9024    fn validate_deps_accepts_canonical_caixa() {
9025        // Positive control: the bare template — zero deps, zero
9026        // deps_dev — passes the gate trivially. A future axis added to
9027        // `Dep::validate` mustn't regress an empty-deps caixa to a
9028        // build error.
9029        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9030        c.validate_deps().unwrap();
9031    }
9032
9033    #[test]
9034    fn validate_deps_rejects_invalid_versao_in_deps() {
9035        // Fail-before-pass-after pin: a malformed `:deps :versao`
9036        // surfaces at validate_deps() time, not at lacre-resolve time.
9037        // Mirrors `rejects_invalid_membro_versao_requirement` and
9038        // `validate_rejects_invalid_child_versao_requirement` on the
9039        // other two `:versao` axes.
9040        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9041        c.deps = vec![Dep::simple("caixa-teia", "^bad-version")];
9042        let err = c.validate_deps().unwrap_err();
9043        assert!(
9044            matches!(
9045                err,
9046                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9047                    if nome == "caixa-teia" && versao == "^bad-version"
9048            ),
9049            "got {err:?}"
9050        );
9051    }
9052
9053    #[test]
9054    fn validate_deps_rejects_invalid_versao_in_deps_dev() {
9055        // Parity pin: `:deps-dev` must run through the same per-entry
9056        // validator as `:deps` — a typo in either axis surfaces the
9057        // same diagnostic. Without this leg, `:deps-dev` would be a
9058        // second-class citizen of the typed surface and an author
9059        // could land a build that passes validate_deps but fails at
9060        // `feira lock`-time when the dev-dep is resolved for a test
9061        // build.
9062        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9063        c.deps_dev = vec![Dep::simple("tatara-check", "^^0.1")];
9064        let err = c.validate_deps().unwrap_err();
9065        assert!(
9066            matches!(
9067                err,
9068                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9069                    if nome == "tatara-check" && versao == "^^0.1"
9070            ),
9071            "got {err:?}"
9072        );
9073    }
9074
9075    #[test]
9076    fn validate_deps_runs_deps_before_deps_dev() {
9077        // Order pin: when both lists carry typos, the `:deps`
9078        // diagnostic surfaces first. The author's mental model is
9079        // "runtime deps are load-bearing; dev deps are scaffolding";
9080        // surfacing the runtime axis first matches that hierarchy.
9081        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9082        c.deps = vec![Dep::simple("runtime-dep", "^bad-runtime")];
9083        c.deps_dev = vec![Dep::simple("dev-dep", "^bad-dev")];
9084        let err = c.validate_deps().unwrap_err();
9085        assert!(
9086            matches!(
9087                err,
9088                crate::dep::DepError::VersaoInvalid { ref nome, .. }
9089                    if nome == "runtime-dep"
9090            ),
9091            "expected `:deps` typo to surface first, got {err:?}"
9092        );
9093    }
9094
9095    #[test]
9096    fn validate_deps_accepts_canonical_versao_forms_in_both_lists() {
9097        // Positive control sweep across both lists. Pin every
9098        // canonical Cargo-shaped form so a future tightening of the
9099        // accepted set surfaces here as a test failure (parity with
9100        // `accepts_canonical_membro_versao_forms` and
9101        // `validate_accepts_canonical_child_versao_forms`).
9102        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9103        c.deps = vec![
9104            Dep::simple("caret", "^0.1"),
9105            Dep::simple("tilde", "~0.1.2"),
9106            Dep::simple("exact", "0.1.0"),
9107            Dep::simple("wildcard", "*"),
9108            Dep::simple("multi-range", ">=0.1, <2"),
9109        ];
9110        c.deps_dev = vec![
9111            Dep::simple("dev-caret", "^0.1"),
9112            Dep::simple("dev-wildcard", "*"),
9113        ];
9114        c.validate_deps().unwrap();
9115    }
9116
9117    #[test]
9118    fn validate_deps_diagnostic_carries_offending_dep() {
9119        // Diagnostic-shape pin: the error names the offending entry's
9120        // `:nome` + `:versao` verbatim and carries a non-empty
9121        // `reason` from `semver::VersionReq::parse`, so a `feira lint`
9122        // run can render the diagnostic without re-parsing.
9123        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9124        c.deps = vec![Dep::simple("caixa-teia", "not-a-req")];
9125        let err = c.validate_deps().unwrap_err();
9126        let crate::dep::DepError::VersaoInvalid {
9127            nome,
9128            versao,
9129            reason,
9130        } = err
9131        else {
9132            panic!("expected VersaoInvalid, got other variant");
9133        };
9134        assert_eq!(nome, "caixa-teia");
9135        assert_eq!(versao, "not-a-req");
9136        assert!(
9137            !reason.is_empty(),
9138            "VersaoInvalid `reason` must carry the parser's wording verbatim"
9139        );
9140    }
9141
9142    #[test]
9143    fn validate_deps_rejects_ambiguous_fonte_in_deps_dev() {
9144        // Cross-axis pin: `validate_deps` walks both :deps and
9145        // :deps-dev through `Dep::validate`, and the new fonte gate
9146        // (`:tag` + `:branch` both set — the canonical "pin drift"
9147        // footgun) must surface from the :deps-dev arm with the
9148        // offending entry's :nome named. Pin the :deps-dev arm
9149        // explicitly so a future shortcut that only walks :deps
9150        // surfaces here as a regression.
9151        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9152        c.deps_dev = vec![Dep {
9153            nome: "dev-only".into(),
9154            versao: "^0.1".into(),
9155            fonte: Some(crate::DepSource::Git {
9156                repo: "github:p/x".into(),
9157                tag: Some("v1".into()),
9158                rev: None,
9159                branch: Some("main".into()),
9160            }),
9161            opcional: false,
9162            caracteristicas: vec![],
9163        }];
9164        let err = c.validate_deps().unwrap_err();
9165        let crate::dep::DepError::FontePinAmbiguous { nome, pins } = err else {
9166            panic!("expected FontePinAmbiguous from :deps-dev walk");
9167        };
9168        assert_eq!(nome, "dev-only");
9169        assert!(pins.contains(":tag") && pins.contains(":branch"));
9170    }
9171
9172    #[test]
9173    fn validate_deps_rejects_empty_repo_in_deps() {
9174        // Parity pin on the :deps arm: an empty :repo on the runtime
9175        // deps list surfaces the same FonteRepoEmpty diagnostic the
9176        // dep.rs per-entry tests pin, naming the offending entry.
9177        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9178        c.deps = vec![Dep {
9179            nome: "runtime".into(),
9180            versao: "^0.1".into(),
9181            fonte: Some(crate::DepSource::Git {
9182                repo: String::new(),
9183                tag: Some("v1".into()),
9184                rev: None,
9185                branch: None,
9186            }),
9187            opcional: false,
9188            caracteristicas: vec![],
9189        }];
9190        let err = c.validate_deps().unwrap_err();
9191        assert!(
9192            matches!(
9193                err,
9194                crate::dep::DepError::FonteRepoEmpty { ref nome }
9195                    if nome == "runtime"
9196            ),
9197            "got {err:?}"
9198        );
9199    }
9200
9201    // ── validate_deps: within-list :nome set-not-multiset gate ─────────
9202
9203    #[test]
9204    fn validate_deps_rejects_duplicate_nome_in_deps() {
9205        // Fail-before-pass-after pin: two `:deps` entries naming the same
9206        // caixa carry two `:versao` / `:fonte` / feature triples that the
9207        // caixa-resolver's lacre pipeline collapses (the second silently
9208        // overwrites the first at `concrete_versao`-resolve time). The
9209        // gate surfaces the duplicate at validate-time, naming the
9210        // offending caixa + the list, before the resolver-side silent
9211        // drop. Mirrors the peer typed-graph duplicate gates
9212        // (`DuplicateChildCaixa`, `MembroDuplicate`, `DuplicateFrom`, …).
9213        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9214        c.deps = vec![
9215            Dep::simple("caixa-teia", "^0.1"),
9216            Dep::simple("caixa-teia", "^0.2"),
9217        ];
9218        let err = c.validate_deps().unwrap_err();
9219        assert!(
9220            matches!(
9221                err,
9222                crate::dep::DepError::DuplicateNome { ref nome, list }
9223                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9224            ),
9225            "got {err:?}"
9226        );
9227    }
9228
9229    #[test]
9230    fn validate_deps_rejects_duplicate_nome_in_deps_dev() {
9231        // Parity pin: `:deps-dev` runs through the same per-list
9232        // duplicate check as `:deps` — neither axis is a second-class
9233        // citizen of the set-not-multiset discipline.
9234        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9235        c.deps_dev = vec![
9236            Dep::simple("tatara-check", "*"),
9237            Dep::simple("tatara-check", "^0.1"),
9238        ];
9239        let err = c.validate_deps().unwrap_err();
9240        assert!(
9241            matches!(
9242                err,
9243                crate::dep::DepError::DuplicateNome { ref nome, list }
9244                    if nome == "tatara-check" && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
9245            ),
9246            "got {err:?}"
9247        );
9248    }
9249
9250    #[test]
9251    fn validate_deps_accepts_cross_list_same_nome() {
9252        // The Cargo `[dependencies]` + `[dev-dependencies]` override
9253        // convention is preserved: a name appearing in *both* lists is
9254        // valid (the dev-pin overrides at test/dev time). Only
9255        // within-list duplicates are structurally incoherent — pin the
9256        // permissive cross-list semantics so a future shortcut that
9257        // collapses the two seen-sets into one surfaces here as a test
9258        // failure.
9259        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9260        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
9261        c.deps_dev = vec![Dep::simple("caixa-teia", "^0.2")];
9262        c.validate_deps().unwrap();
9263    }
9264
9265    #[test]
9266    fn validate_deps_accepts_distinct_nome_in_both_lists() {
9267        // Positive control: distinct names within each list pass — the
9268        // gate's identity element on the canonical authoring shape.
9269        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9270        c.deps = vec![
9271            Dep::simple("caixa-teia", "^0.1"),
9272            Dep::simple("pleme-mesh", "*"),
9273        ];
9274        c.deps_dev = vec![
9275            Dep::simple("tatara-check", "*"),
9276            Dep::simple("dev-shim", "^0.1"),
9277        ];
9278        c.validate_deps().unwrap();
9279    }
9280
9281    #[test]
9282    fn validate_deps_per_entry_validate_fires_before_duplicate_in_deps() {
9283        // Diagnostic-precedence pin: a malformed `:versao` on the
9284        // duplicating entry surfaces its narrower `VersaoInvalid`
9285        // diagnostic first, before the cross-entry duplicate gate fires
9286        // — the canonical "per-entry shape before cross-entry uniqueness"
9287        // precedence every peer set-not-multiset gate establishes
9288        // (`*_invalid_fires_before_duplicate_check` pins on
9289        // `SupervisorSpec::validate`, `AplicacaoSpec::validate_membros`,
9290        // `validate_upgrade_from`).
9291        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9292        c.deps = vec![
9293            Dep::simple("caixa-teia", "^0.1"),
9294            Dep::simple("caixa-teia", "^bad-version"),
9295        ];
9296        let err = c.validate_deps().unwrap_err();
9297        assert!(
9298            matches!(
9299                err,
9300                crate::dep::DepError::VersaoInvalid { ref nome, ref versao, .. }
9301                    if nome == "caixa-teia" && versao == "^bad-version"
9302            ),
9303            "expected VersaoInvalid to surface before DuplicateNome, got {err:?}"
9304        );
9305    }
9306
9307    #[test]
9308    fn validate_deps_duplicate_diagnostic_names_first_collision() {
9309        // First-collision determinism pin: with three entries naming the
9310        // same caixa, the first colliding pair surfaces — not the last.
9311        // Mirrors the peer first-collision posture on every
9312        // duplicate-target gate
9313        // (`validate_upgrade_from_duplicate_diagnostic_names_second_collision`
9314        // — the second entry is the first collision; this gate uses the
9315        // same shape: the second entry's `:nome` lands in the diagnostic
9316        // because `seen.insert(first.nome)` already populated the set).
9317        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9318        c.deps = vec![
9319            Dep::simple("caixa-teia", "^0.1"),
9320            Dep::simple("caixa-teia", "^0.2"),
9321            Dep::simple("caixa-teia", "^0.3"),
9322        ];
9323        let err = c.validate_deps().unwrap_err();
9324        // The diagnostic carries the offending caixa name; the
9325        // implementation surfaces on the *second* entry (the first
9326        // collision), so the test pins the `:nome` value.
9327        assert!(
9328            matches!(
9329                err,
9330                crate::dep::DepError::DuplicateNome { ref nome, list }
9331                    if nome == "caixa-teia" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9332            ),
9333            "got {err:?}"
9334        );
9335    }
9336
9337    #[test]
9338    fn validate_deps_duplicate_in_deps_fires_before_duplicate_in_deps_dev() {
9339        // Cross-list precedence pin: when both lists carry duplicates,
9340        // the `:deps` diagnostic surfaces first — same author-mental-
9341        // model ordering the `validate_deps_runs_deps_before_deps_dev`
9342        // pin establishes for malformed `:versao` (runtime axis before
9343        // dev axis).
9344        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9345        c.deps = vec![
9346            Dep::simple("runtime-dep", "^0.1"),
9347            Dep::simple("runtime-dep", "^0.2"),
9348        ];
9349        c.deps_dev = vec![Dep::simple("dev-dep", "*"), Dep::simple("dev-dep", "^0.1")];
9350        let err = c.validate_deps().unwrap_err();
9351        assert!(
9352            matches!(
9353                err,
9354                crate::dep::DepError::DuplicateNome { ref nome, list }
9355                    if nome == "runtime-dep" && list == crate::render::DEP_AUTHOR_KEY_DEPS
9356            ),
9357            "expected :deps duplicate to surface before :deps-dev duplicate, got {err:?}"
9358        );
9359    }
9360
9361    #[test]
9362    fn validate_deps_empty_lists_pass_duplicate_gate() {
9363        // Empty-set identity pin: the bare template (zero deps, zero
9364        // deps_dev) passes the duplicate gate as the gate's identity
9365        // element. A future tighten that conflates "empty" with
9366        // "missing" would regress this baseline.
9367        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9368        c.validate_deps().unwrap();
9369    }
9370
9371    #[test]
9372    fn validate_deps_duplicate_diagnostic_carries_list_tag() {
9373        // Diagnostic-shape pin: the `list:` field tags which list the
9374        // duplicate landed in (`:deps` vs `:deps-dev`) verbatim, so a
9375        // `feira lint` run can route the author to the right block in
9376        // their caixa.lisp without re-deriving the list from context.
9377        // Same self-locating shape every peer per-axis diagnostic
9378        // already exposes.
9379        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9380        c.deps_dev = vec![
9381            Dep::simple("dev-thing", "*"),
9382            Dep::simple("dev-thing", "^0.1"),
9383        ];
9384        let err = c.validate_deps().unwrap_err();
9385        let crate::dep::DepError::DuplicateNome { nome, list } = err else {
9386            panic!("expected DuplicateNome from :deps-dev walk");
9387        };
9388        assert_eq!(nome, "dev-thing");
9389        assert_eq!(list, crate::render::DEP_AUTHOR_KEY_DEPS_DEV);
9390    }
9391
9392    // ── validate_deps: per-entry :caracteristicas set-discipline gate ──
9393
9394    #[test]
9395    fn validate_deps_surfaces_caracteristicas_duplicate_in_deps_list() {
9396        // Thread-through pin on `:deps`: the per-entry
9397        // `Dep::validate_caracteristicas` gate fires inside
9398        // `Caixa::validate_deps`'s linear walk, so a malformed feature
9399        // list on any `:deps` entry surfaces as a `DepError` from
9400        // `validate_deps` — the same reachability shape every per-entry
9401        // `Dep::validate` arm threads through. Without this pin a future
9402        // shortcut that skips the per-entry `Dep::validate` call on the
9403        // cross-entry-uniqueness path would mask the within-entry
9404        // `:caracteristicas` gates.
9405        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9406        c.deps = vec![Dep {
9407            nome: "caixa-teia".into(),
9408            versao: "^0.1".into(),
9409            fonte: None,
9410            opcional: false,
9411            caracteristicas: vec!["http".into(), "http".into()],
9412        }];
9413        let err = c.validate_deps().unwrap_err();
9414        let crate::dep::DepError::CaracteristicaDuplicate {
9415            nome,
9416            caracteristica,
9417        } = err
9418        else {
9419            panic!("expected CaracteristicaDuplicate from :deps walk, got {err:?}");
9420        };
9421        assert_eq!(nome, "caixa-teia");
9422        assert_eq!(caracteristica, "http");
9423    }
9424
9425    #[test]
9426    fn validate_deps_surfaces_caracteristicas_empty_in_deps_dev_list() {
9427        // Peer thread-through pin on `:deps-dev`: same reachability as
9428        // the `:deps` arm above, on the dev-only authoring axis. Pins
9429        // that the `validate_deps` walk visits both lists' per-entry
9430        // gates uniformly. The empty-feature arm carries here so both
9431        // new `:caracteristicas` arms are surfaced via at least one
9432        // `validate_deps` thread-through.
9433        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9434        c.deps_dev = vec![Dep {
9435            nome: "caixa-teia".into(),
9436            versao: "^0.1".into(),
9437            fonte: None,
9438            opcional: false,
9439            caracteristicas: vec![String::new()],
9440        }];
9441        let err = c.validate_deps().unwrap_err();
9442        let crate::dep::DepError::CaracteristicaEmpty { nome } = err else {
9443            panic!("expected CaracteristicaEmpty from :deps-dev walk, got {err:?}");
9444        };
9445        assert_eq!(nome, "caixa-teia");
9446    }
9447
9448    #[test]
9449    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_list() {
9450        // Thread-through pin on `:deps`: the per-entry
9451        // `Dep::validate_caracteristicas` value-shape gate (lifted via
9452        // `crate::render::is_cargo_feature_name`) fires inside
9453        // `Caixa::validate_deps`'s linear walk on the `:deps` list, so
9454        // a structurally invalid feature name on any `:deps` entry
9455        // surfaces as `DepError::CaracteristicaInvalid` from
9456        // `validate_deps` — the same reachability shape every per-entry
9457        // `Dep::validate` arm threads through. Without this pin a
9458        // future shortcut that skips the per-entry `Dep::validate` call
9459        // on the cross-entry-uniqueness path would mask the within-
9460        // entry `:caracteristicas` value-shape gate.
9461        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9462        c.deps = vec![Dep {
9463            nome: "caixa-teia".into(),
9464            versao: "^0.1".into(),
9465            fonte: None,
9466            opcional: false,
9467            caracteristicas: vec!["+http".into()],
9468        }];
9469        let err = c.validate_deps().unwrap_err();
9470        let crate::dep::DepError::CaracteristicaInvalid {
9471            nome,
9472            caracteristica,
9473            ..
9474        } = err
9475        else {
9476            panic!("expected CaracteristicaInvalid from :deps walk, got {err:?}");
9477        };
9478        assert_eq!(nome, "caixa-teia");
9479        assert_eq!(caracteristica, "+http");
9480    }
9481
9482    #[test]
9483    fn validate_deps_surfaces_caracteristicas_invalid_in_deps_dev_list() {
9484        // Peer thread-through pin on `:deps-dev`: same reachability as
9485        // the `:deps` arm above, on the dev-only authoring axis. The
9486        // `http/json` shape carries here so the segment-separator
9487        // diagnostic (the canonical Cargo `dep/feat` namespaced-dep
9488        // confusion footgun) is surfaced via the cross-entry walk too —
9489        // pinning that the `:deps-dev` list visits the same per-entry
9490        // value-shape gate as the `:deps` list.
9491        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9492        c.deps_dev = vec![Dep {
9493            nome: "caixa-teia".into(),
9494            versao: "^0.1".into(),
9495            fonte: None,
9496            opcional: false,
9497            caracteristicas: vec!["http/json".into()],
9498        }];
9499        let err = c.validate_deps().unwrap_err();
9500        let crate::dep::DepError::CaracteristicaInvalid {
9501            nome,
9502            caracteristica,
9503            ..
9504        } = err
9505        else {
9506            panic!("expected CaracteristicaInvalid from :deps-dev walk, got {err:?}");
9507        };
9508        assert_eq!(nome, "caixa-teia");
9509        assert_eq!(caracteristica, "http/json");
9510    }
9511
9512    #[test]
9513    fn to_lisp_preserves_deps() {
9514        let src = r#"
9515(defcaixa
9516  :nome "x"
9517  :versao "0.1.0"
9518  :kind Biblioteca
9519  :deps ((:nome "a" :versao "^0.1")
9520         (:nome "b" :versao "*" :fonte (:tipo git :repo "github:o/b" :tag "v1"))))
9521"#;
9522        let c1 = Caixa::from_lisp(src).unwrap();
9523        let emitted = c1.to_lisp();
9524        let c2 = Caixa::from_lisp(&emitted).expect("round trip");
9525        assert_eq!(c1.deps, c2.deps);
9526    }
9527
9528    // ── Caixa::validate_nome — top-level :nome value-shape gate ─────────
9529
9530    fn caixa_with_nome(nome: &str) -> Caixa {
9531        let mut c = Caixa::from_lisp(&Caixa::template("placeholder")).unwrap();
9532        c.nome = nome.to_string();
9533        c
9534    }
9535
9536    #[test]
9537    fn validate_nome_accepts_canonical_template() {
9538        // Positive control: the bare `feira init`-style template's
9539        // `:nome` ("demo") is a canonical DNS-1123 label; the gate must
9540        // not regress this baseline shape. A future tightening of the
9541        // accepted set surfaces here as a test failure first.
9542        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9543        c.validate_nome().unwrap();
9544    }
9545
9546    #[test]
9547    fn validate_nome_accepts_canonical_forms() {
9548        // Positive-set sweep: each realistic caixa-name shape the K8s
9549        // apiserver accepts as a `metadata.name` label must pass —
9550        // single-word, hyphen-joined, version-suffixed, single-char,
9551        // two-char, digit-start (DNS-1123 allows this; the stricter
9552        // DNS-1035 Service-name rule doesn't), version-suffix-bearing.
9553        // Mirrors `accepts_canonical_membro_caixa_forms` (3f9d7a0) on
9554        // the peer member-name axis.
9555        for nome in [
9556            "checkout",
9557            "cart-v2",
9558            "a",
9559            "db",
9560            "3rd-party-shim",
9561            "payment-retry",
9562            "0",
9563        ] {
9564            caixa_with_nome(nome)
9565                .validate_nome()
9566                .unwrap_or_else(|e| panic!("canonical :nome {nome:?} must validate, got {e:?}"));
9567        }
9568    }
9569
9570    #[test]
9571    fn validate_nome_rejects_empty() {
9572        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
9573        // an empty `:nome` (the derive macro stores the raw String);
9574        // the gate's empty arm names the offending axis with a narrower
9575        // diagnostic than the `NomeInvalid` parse arm would emit.
9576        let c = caixa_with_nome("");
9577        let err = c.validate_nome().unwrap_err();
9578        assert_eq!(err, ManifestError::NomeEmpty);
9579    }
9580
9581    #[test]
9582    fn validate_nome_rejects_uppercase() {
9583        // The canonical "I copied the TitleCase display name verbatim"
9584        // footgun. The K8s apiserver rejects `metadata.name: MyApp` at
9585        // admission on every derived artifact (Helm chart, ComputeUnit,
9586        // CNP, HTTPRoute, label values); the gate moves the diagnostic
9587        // to the source `caixa.lisp` and the reason suggests the
9588        // lowercased fix verbatim.
9589        let c = caixa_with_nome("MyApp");
9590        let err = c.validate_nome().unwrap_err();
9591        let ManifestError::NomeInvalid { nome, reason } = err else {
9592            panic!("expected NomeInvalid for uppercase :nome");
9593        };
9594        assert_eq!(nome, "MyApp");
9595        assert!(
9596            reason.contains("uppercase") && reason.contains("myapp"),
9597            "diagnostic must name the violation + the lowercased fix, got {reason:?}"
9598        );
9599    }
9600
9601    #[test]
9602    fn validate_nome_rejects_underscore() {
9603        // The Python-/Postgres-style `snake_case` leak. DNS-1123 forbids
9604        // `_`; the apiserver rejects on admission across every derived
9605        // artifact. Same fixture pinned for `:membros :caixa` (3f9d7a0)
9606        // and `:children :caixa` (31bfa43).
9607        let c = caixa_with_nome("my_app");
9608        let err = c.validate_nome().unwrap_err();
9609        assert!(
9610            matches!(
9611                err,
9612                ManifestError::NomeInvalid { ref nome, ref reason }
9613                    if nome == "my_app" && reason.contains('_')
9614            ),
9615            "got {err:?}"
9616        );
9617    }
9618
9619    #[test]
9620    fn validate_nome_rejects_dot() {
9621        // A `:nome` is a single DNS-1123 label, not a subdomain. The
9622        // "I want to namespace with `.`" footgun the gate redirects to
9623        // `-` via the shared predicate's reason wording.
9624        let c = caixa_with_nome("team.app");
9625        let err = c.validate_nome().unwrap_err();
9626        assert!(
9627            matches!(
9628                err,
9629                ManifestError::NomeInvalid { ref nome, ref reason }
9630                    if nome == "team.app" && reason.contains('.')
9631            ),
9632            "got {err:?}"
9633        );
9634    }
9635
9636    #[test]
9637    fn validate_nome_rejects_leading_hyphen() {
9638        // DNS-1123 boundary rule: the label must start with an ASCII
9639        // alphanumeric. Pin the leading-`-` arm explicitly.
9640        let c = caixa_with_nome("-app");
9641        let err = c.validate_nome().unwrap_err();
9642        assert!(
9643            matches!(
9644                err,
9645                ManifestError::NomeInvalid { ref nome, .. } if nome == "-app"
9646            ),
9647            "got {err:?}"
9648        );
9649    }
9650
9651    #[test]
9652    fn validate_nome_rejects_trailing_hyphen() {
9653        // Symmetric arm of the boundary rule, pinned separately so a
9654        // future relaxation that only checks the leading position
9655        // surfaces here. Mirrors `rejects_membro_caixa_with_trailing_hyphen`
9656        // and `_with_trailing_hyphen` on the supervisor / aplicacao
9657        // axes.
9658        let c = caixa_with_nome("app-");
9659        let err = c.validate_nome().unwrap_err();
9660        assert!(
9661            matches!(
9662                err,
9663                ManifestError::NomeInvalid { ref nome, .. } if nome == "app-"
9664            ),
9665            "got {err:?}"
9666        );
9667    }
9668
9669    #[test]
9670    fn validate_nome_rejects_unicode() {
9671        // IDN must be pre-encoded as Punycode (`xn--…`); raw Unicode
9672        // bytes are rejected by the K8s apiserver on every name axis.
9673        let c = caixa_with_nome("café");
9674        let err = c.validate_nome().unwrap_err();
9675        assert!(
9676            matches!(
9677                err,
9678                ManifestError::NomeInvalid { ref nome, .. } if nome == "café"
9679            ),
9680            "got {err:?}"
9681        );
9682    }
9683
9684    #[test]
9685    fn validate_nome_rejects_whitespace() {
9686        // The paste-from-sketch / paste-from-spec footgun. Internal
9687        // whitespace is rejected by every K8s name axis.
9688        let c = caixa_with_nome("my app");
9689        let err = c.validate_nome().unwrap_err();
9690        assert!(
9691            matches!(
9692                err,
9693                ManifestError::NomeInvalid { ref nome, .. } if nome == "my app"
9694            ),
9695            "got {err:?}"
9696        );
9697    }
9698
9699    #[test]
9700    fn validate_nome_rejects_too_long() {
9701        // 64-byte boundary pin: the K8s apiserver rejects any
9702        // `metadata.name` over 63 bytes at admission; the diagnostic
9703        // names both the 63-byte cap and the actual length so the
9704        // author can shorten in one edit. Mirrors `_too_long` on the
9705        // peer member-/cluster-/child-name axes.
9706        let over = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN + 1);
9707        let c = caixa_with_nome(&over);
9708        let err = c.validate_nome().unwrap_err();
9709        let ManifestError::NomeInvalid { nome, reason } = err else {
9710            panic!("expected NomeInvalid for over-cap :nome");
9711        };
9712        assert_eq!(nome.len(), crate::DNS_1123_LABEL_MAX_LEN + 1);
9713        assert!(
9714            reason.contains("63") && reason.contains("64"),
9715            "diagnostic must name the cap + actual length, got {reason:?}"
9716        );
9717    }
9718
9719    #[test]
9720    fn nome_max_length_validates() {
9721        // The 63-byte cap exactly — the boundary-accepting case pinned
9722        // alongside `validate_nome_rejects_too_long` so a future cap
9723        // shift surfaces both arms simultaneously. Mirrors
9724        // `membro_caixa_max_length_validates`,
9725        // `placement_cluster_max_length_validates`,
9726        // `child_caixa_max_length_validates`.
9727        let at_cap = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
9728        caixa_with_nome(&at_cap).validate_nome().unwrap();
9729    }
9730
9731    #[test]
9732    fn nome_empty_takes_precedence_over_invalid() {
9733        // Order pin: the empty arm fires before the predicate is
9734        // consulted. Empty < invalid in self-locating-ness — the
9735        // narrower `NomeEmpty` diagnostic doesn't carry a useless
9736        // `nome: ""` reference into the parser-shaped reason. Mirrors
9737        // `membro_caixa_empty_takes_precedence_over_invalid` on the
9738        // peer axis (3f9d7a0).
9739        let c = caixa_with_nome("");
9740        assert_eq!(c.validate_nome().unwrap_err(), ManifestError::NomeEmpty);
9741    }
9742
9743    #[test]
9744    fn nome_invalid_diagnostic_carries_offending_nome() {
9745        // Diagnostic-shape pin: the error names the offending `:nome`
9746        // verbatim with a non-empty parser-shaped reason, so a `feira
9747        // lint` run can render the diagnostic without re-parsing.
9748        // Mirrors `membro_caixa_invalid_diagnostic_carries_offending_caixa`.
9749        let c = caixa_with_nome("MyApp");
9750        let err = c.validate_nome().unwrap_err();
9751        let ManifestError::NomeInvalid { nome, reason } = err else {
9752            panic!("expected NomeInvalid variant");
9753        };
9754        assert_eq!(nome, "MyApp");
9755        assert!(
9756            !reason.is_empty(),
9757            "NomeInvalid `reason` must carry the predicate's wording verbatim"
9758        );
9759    }
9760
9761    // ── Caixa::validate_nome_chart_name_budget — joint-length on `:nome` ──
9762    //
9763    // The bare-`:nome` axis [`Caixa::validate_nome`] caps at 63 bytes
9764    // via DNS-1123; this second-axis gate caps the joint
9765    // `lareira-<nome>` chart name at the same 63-byte ceiling. The
9766    // canonical [`crate::lareira_chart_name`] helper's doc comment
9767    // (f7320d7, caixa-core/src/render.rs:3198) explicitly deferred:
9768    // "the M4 admission webhook will pin the joint-length invariant
9769    // when it lands". These tests pin it at the manifest-validate
9770    // layer instead, fail-before-pass-after on the 56-byte boundary.
9771
9772    #[test]
9773    fn validate_nome_chart_name_budget_accepts_canonical_template() {
9774        // Positive control: the bare `feira init`-style template's
9775        // `:nome` ("demo") sits far below the cap; the gate must not
9776        // regress this baseline. Same shape every peer
9777        // value-shape-gate baseline pin uses.
9778        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9779        c.validate_nome_chart_name_budget().unwrap();
9780    }
9781
9782    #[test]
9783    fn validate_nome_chart_name_budget_accepts_canonical_fixtures() {
9784        // Positive-set sweep across the canonical author surface every
9785        // in-tree fixture uses (`hello-rio`, `cart`, `checkout`,
9786        // `worker`, the `checkout-aplicacao` example members, the
9787        // `example-attest` caixa-tatara fixture). Every value sits
9788        // far below the 55-byte per-`:nome` budget. Same shape every
9789        // peer per-axis baseline pin uses.
9790        for nome in [
9791            "hello-rio",
9792            "cart",
9793            "checkout",
9794            "worker",
9795            "example-attest",
9796            "demo",
9797            "a",
9798        ] {
9799            caixa_with_nome(nome)
9800                .validate_nome_chart_name_budget()
9801                .unwrap_or_else(|e| {
9802                    panic!("canonical :nome {nome:?} must pass chart-name budget, got {e:?}")
9803                });
9804        }
9805    }
9806
9807    #[test]
9808    fn validate_nome_chart_name_budget_accepts_nome_at_cap() {
9809        // Boundary-accepting case at the 55-byte per-`:nome` budget —
9810        // the joint chart name is exactly 63 bytes, the DNS-1123 label
9811        // cap. Pinned alongside the rejecting-arm test so a future cap
9812        // shift surfaces both arms simultaneously. Mirrors
9813        // `nome_max_length_validates` on the peer bare-`:nome` axis.
9814        let at_cap = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN);
9815        caixa_with_nome(&at_cap)
9816            .validate_nome_chart_name_budget()
9817            .unwrap();
9818    }
9819
9820    #[test]
9821    fn validate_nome_chart_name_budget_rejects_nome_one_over_cap() {
9822        // Fail-before-pass-after pin on the 56-byte boundary: the
9823        // smallest `:nome` length that overflows the joint chart-name
9824        // cap. The inner [`is_dns_1123_label`] gate
9825        // (`Caixa::validate_nome`) accepts it (56 ≤ 63), so prior to
9826        // this gate it silently passed the manifest-validate cascade
9827        // and surfaced as a `helm lint` / apiserver rejection on the
9828        // rendered chart name far from the source `caixa.lisp`, with
9829        // no field naming the overflow. With this gate the diagnostic
9830        // names the offending `:nome` verbatim alongside the rendered
9831        // chart name and the budget, so the author can shorten in one
9832        // edit. Mirrors `validate_nome_rejects_too_long` on the peer
9833        // bare-`:nome` axis.
9834        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9835        let c = caixa_with_nome(&over);
9836        let err = c.validate_nome_chart_name_budget().unwrap_err();
9837        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
9838            panic!("expected NomeChartNameBudgetExceeded for over-budget :nome");
9839        };
9840        assert_eq!(nome.len(), crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9841        assert_eq!(nome, over);
9842        assert!(
9843            reason.contains("63") && reason.contains("64") && reason.contains("55"),
9844            "diagnostic must name the DNS-1123 cap (63), the actual chart-name length (64), \
9845             and the per-`:nome` budget (55), got {reason:?}"
9846        );
9847    }
9848
9849    #[test]
9850    fn validate_nome_chart_name_budget_rejects_nome_at_bare_dns_cap() {
9851        // The 63-byte `:nome` boundary — passes the bare-`:nome`
9852        // [`is_dns_1123_label`] cap exactly, but produces a 71-byte
9853        // joint chart name that overflows the DNS-1123 label cap
9854        // structurally. The most stringent fail-before-pass-after
9855        // surface: every `:nome` in the 56..=63-byte range passed the
9856        // prior cascade and broke at admission.
9857        let bare_max = "a".repeat(crate::DNS_1123_LABEL_MAX_LEN);
9858        let c = caixa_with_nome(&bare_max);
9859        // The bare-`:nome` gate accepts the 63-byte length.
9860        c.validate_nome().unwrap();
9861        // The new joint-length gate rejects it.
9862        let err = c.validate_nome_chart_name_budget().unwrap_err();
9863        assert!(
9864            matches!(
9865                err,
9866                ManifestError::NomeChartNameBudgetExceeded { ref nome, .. }
9867                    if nome.len() == crate::DNS_1123_LABEL_MAX_LEN
9868            ),
9869            "got {err:?}"
9870        );
9871    }
9872
9873    #[test]
9874    fn validate_nome_chart_name_budget_diagnostic_carries_offending_chart_name() {
9875        // Diagnostic-shape pin: the rendered `lareira-<nome>` chart
9876        // name appears verbatim in the diagnostic so the author sees
9877        // exactly the string the apiserver / `helm lint` would have
9878        // rejected — no re-derivation required to grep the source.
9879        // Peer with `nome_invalid_diagnostic_carries_offending_nome`
9880        // on the bare-`:nome` axis.
9881        let over = "x".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 5);
9882        let c = caixa_with_nome(&over);
9883        let err = c.validate_nome_chart_name_budget().unwrap_err();
9884        let ManifestError::NomeChartNameBudgetExceeded { nome, reason } = err else {
9885            panic!("expected NomeChartNameBudgetExceeded variant");
9886        };
9887        assert_eq!(nome, over);
9888        let expected_chart = crate::lareira_chart_name(&over);
9889        assert!(
9890            reason.contains(&expected_chart),
9891            "diagnostic must carry the rendered chart name {expected_chart:?} verbatim, \
9892             got {reason:?}"
9893        );
9894        assert!(
9895            reason.contains("lareira-"),
9896            "diagnostic must name the canonical chart-name prefix verbatim, got {reason:?}"
9897        );
9898    }
9899
9900    #[test]
9901    fn validate_nome_chart_name_budget_runs_after_nome_shape_via_layout_verify() {
9902        // Order pin on the layout cascade: the narrower
9903        // `NomeInvalid` (bare-DNS-1123 shape) fires before the
9904        // joint-length budget. A structurally-malformed `:nome` (here:
9905        // uppercase) surfaces its specific shape error rather than
9906        // the chart-name-budget error, even when the joint length
9907        // would also overflow — the narrower diagnostic is more
9908        // self-locating. Mirrors the cascade-precedence pins peer
9909        // gates already use (e.g. `EntradaParaEmpty` before
9910        // `EntradaParaInvalid`).
9911        let over = "A".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9912        let c = caixa_with_nome(&over);
9913        // The bare-shape gate fires first.
9914        let err = c.validate_nome().unwrap_err();
9915        assert!(
9916            matches!(err, ManifestError::NomeInvalid { .. }),
9917            "bare-shape gate must fire before chart-name-budget gate; got {err:?}"
9918        );
9919        // And the layout verify cascade surfaces that diagnostic, not
9920        // the budget arm. Inject a path-exists oracle so the cascade
9921        // gets past the manifest-presence check and into the
9922        // value-shape gates.
9923        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
9924        let err = crate::LayoutInvariants::verify(
9925            &layout,
9926            &c,
9927            std::path::Path::new("/tmp/caixa-test-fake-root"),
9928        )
9929        .unwrap_err();
9930        let issue = err.to_string();
9931        assert!(
9932            issue.contains("DNS-1123") || issue.contains("uppercase"),
9933            "layout cascade must surface the bare-DNS-1123 diagnostic on a \
9934             structurally-malformed :nome, not the chart-name-budget diagnostic; got {issue:?}"
9935        );
9936    }
9937
9938    #[test]
9939    fn layout_verify_routes_chart_name_budget_through_nome_violation() {
9940        // Cross-axis envelope pin: the layout cascade wraps both
9941        // bare-`:nome` and joint-length-`:nome` failures through the
9942        // same [`LayoutError::NomeViolation`] envelope, since both
9943        // arms are on the `:nome` axis. The user's diagnostic stays
9944        // self-locating ("which axis"), and a future consumer that
9945        // dispatches on the layout-error variant (e.g. a `feira lint`
9946        // exit-code mapping) sees a single per-axis envelope. The
9947        // wrapped `issue:` carries the full inner diagnostic.
9948        let over = "a".repeat(crate::LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
9949        let c = caixa_with_nome(&over);
9950        // The bare-shape gate accepts.
9951        c.validate_nome().unwrap();
9952        let layout = crate::StandardLayout::new().with_path_exists(|_| true);
9953        let err = crate::LayoutInvariants::verify(
9954            &layout,
9955            &c,
9956            std::path::Path::new("/tmp/caixa-test-fake-root"),
9957        )
9958        .unwrap_err();
9959        let crate::LayoutError::NomeViolation { caixa, issue } = err else {
9960            panic!("expected LayoutError::NomeViolation, got {err:?}");
9961        };
9962        assert_eq!(caixa, over);
9963        assert!(
9964            issue.contains("lareira-") && issue.contains("63") && issue.contains("55"),
9965            "wrapped issue must carry the joint-length diagnostic verbatim, got {issue:?}"
9966        );
9967    }
9968
9969    // ── Caixa::validate_versao — top-level :versao value-shape gate ─────
9970
9971    fn caixa_with_versao(versao: &str) -> Caixa {
9972        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9973        c.versao = versao.to_string();
9974        c
9975    }
9976
9977    #[test]
9978    fn validate_versao_accepts_canonical_template() {
9979        // Positive control: the bare `feira init`-style template's
9980        // `:versao` ("0.1.0") is a canonical SemVer-2 literal; the gate
9981        // must not regress this baseline shape. A future tightening of
9982        // the accepted set surfaces here as a test failure first.
9983        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
9984        c.validate_versao().unwrap();
9985    }
9986
9987    #[test]
9988    fn validate_versao_accepts_canonical_forms() {
9989        // Positive-set sweep: each realistic SemVer-2 shape the
9990        // substrate's downstream consumers accept must pass — bare
9991        // MAJOR.MINOR.PATCH, pre-release tags (`-rc.1`, `-alpha.0`),
9992        // build metadata (`+build.42`), the combined form, and the
9993        // `0.0.0` boundary case. Mirrors `accepts_canonical_forms` on
9994        // the peer `:nome` axis (6c992f8).
9995        for versao in [
9996            "0.1.0",
9997            "0.0.0",
9998            "1.0.0",
9999            "0.2.0-rc.1",
10000            "1.0.0-alpha.0",
10001            "1.0.0+build.42",
10002            "1.0.0-rc.1+build.42",
10003            "10.20.30",
10004        ] {
10005            caixa_with_versao(versao)
10006                .validate_versao()
10007                .unwrap_or_else(|e| {
10008                    panic!("canonical :versao {versao:?} must validate, got {e:?}")
10009                });
10010        }
10011    }
10012
10013    #[test]
10014    fn validate_versao_rejects_empty() {
10015        // Fail-before-pass-after pin: `Caixa::from_lisp` does not refuse
10016        // an empty `:versao` (the derive macro stores the raw String);
10017        // the gate's empty arm names the offending axis with a narrower
10018        // diagnostic than the `VersaoInvalid` parse arm would emit.
10019        // Mirrors `validate_nome_rejects_empty` (6c992f8).
10020        let c = caixa_with_versao("");
10021        let err = c.validate_versao().unwrap_err();
10022        assert_eq!(err, ManifestError::VersaoEmpty);
10023    }
10024
10025    #[test]
10026    fn validate_versao_rejects_git_tag_shape() {
10027        // The canonical "I copied the git tag verbatim" footgun —
10028        // `feira publish` *emits* `v<versao>` git tags, so a leaked
10029        // `v0.1.0` in `:versao` would render as `vv0.1.0` and silently
10030        // shift every downstream consumer's version axis. `semver`
10031        // rejects the leading `v` at parse time; the gate moves the
10032        // diagnostic to the source `caixa.lisp`.
10033        let c = caixa_with_versao("v0.1.0");
10034        let err = c.validate_versao().unwrap_err();
10035        let ManifestError::VersaoInvalid { versao, reason } = err else {
10036            panic!("expected VersaoInvalid for git-tag-shape :versao");
10037        };
10038        assert_eq!(versao, "v0.1.0");
10039        assert!(
10040            !reason.is_empty(),
10041            "VersaoInvalid `reason` must carry the parser's wording, got {reason:?}"
10042        );
10043    }
10044
10045    #[test]
10046    fn validate_versao_rejects_missing_patch() {
10047        // The canonical "I shortened it" footgun — SemVer-2 requires
10048        // three parts. Cargo's `version =` field accepts the shortened
10049        // form as a requirement, conflating the two leaks across the
10050        // typed `:deps :versao` vs top-level `:versao` axes; the gate
10051        // pins the top-level axis to the strict three-part shape.
10052        let c = caixa_with_versao("0.1");
10053        let err = c.validate_versao().unwrap_err();
10054        assert!(
10055            matches!(
10056                err,
10057                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1"
10058            ),
10059            "got {err:?}"
10060        );
10061    }
10062
10063    #[test]
10064    fn validate_versao_rejects_requirement_shape() {
10065        // The canonical "I leaked a requirement into a version" footgun —
10066        // the typed `:deps :versao` / `:membros :versao` axes accept
10067        // `^0.1` (a `VersionReq`); the top-level `:versao` requires a
10068        // concrete `Version`. Without this gate the two typed surfaces
10069        // would silently overlap, and a top-level `^0.1` would surface
10070        // at `helm install` time as a Chart.yaml version rejection far
10071        // from the source `caixa.lisp`.
10072        let c = caixa_with_versao("^0.1");
10073        let err = c.validate_versao().unwrap_err();
10074        assert!(
10075            matches!(
10076                err,
10077                ManifestError::VersaoInvalid { ref versao, .. } if versao == "^0.1"
10078            ),
10079            "got {err:?}"
10080        );
10081    }
10082
10083    #[test]
10084    fn validate_versao_rejects_docker_tag_shape() {
10085        // The "I confused it with a docker tag" footgun — `latest`,
10086        // `main`, `stable` parse as identifiers, not SemVer-2 versions.
10087        // SemVer rejects at parse time; the gate moves the diagnostic
10088        // to the source `caixa.lisp`.
10089        for bad in ["latest", "main", "stable"] {
10090            let c = caixa_with_versao(bad);
10091            let err = c.validate_versao().unwrap_err();
10092            assert!(
10093                matches!(
10094                    err,
10095                    ManifestError::VersaoInvalid { ref versao, .. } if versao == bad
10096                ),
10097                "got {err:?} for {bad:?}"
10098            );
10099        }
10100    }
10101
10102    #[test]
10103    fn validate_versao_rejects_four_part_form() {
10104        // The Java/Microsoft "MAJOR.MINOR.PATCH.BUILD" convention
10105        // SemVer-2 forbids. A leak from a non-SemVer ecosystem; the
10106        // semver crate rejects the extra `.0` at parse time.
10107        let c = caixa_with_versao("0.1.0.0");
10108        let err = c.validate_versao().unwrap_err();
10109        assert!(
10110            matches!(
10111                err,
10112                ManifestError::VersaoInvalid { ref versao, .. } if versao == "0.1.0.0"
10113            ),
10114            "got {err:?}"
10115        );
10116    }
10117
10118    #[test]
10119    fn versao_empty_takes_precedence_over_invalid() {
10120        // Order pin: the empty arm fires before the parser is consulted.
10121        // Empty < invalid in self-locating-ness — the narrower
10122        // `VersaoEmpty` diagnostic doesn't carry a useless `versao: ""`
10123        // reference into the parser-shaped reason. Mirrors
10124        // `nome_empty_takes_precedence_over_invalid` (6c992f8) on the
10125        // peer axis.
10126        let c = caixa_with_versao("");
10127        assert_eq!(c.validate_versao().unwrap_err(), ManifestError::VersaoEmpty);
10128    }
10129
10130    #[test]
10131    fn versao_invalid_diagnostic_carries_offending_versao() {
10132        // Diagnostic-shape pin: the error names the offending `:versao`
10133        // verbatim with a non-empty parser-shaped reason, so a `feira
10134        // lint` run can render the diagnostic without re-parsing.
10135        // Mirrors `nome_invalid_diagnostic_carries_offending_nome`.
10136        let c = caixa_with_versao("v0.1.0");
10137        let err = c.validate_versao().unwrap_err();
10138        let ManifestError::VersaoInvalid { versao, reason } = err else {
10139            panic!("expected VersaoInvalid variant");
10140        };
10141        assert_eq!(versao, "v0.1.0");
10142        assert!(
10143            !reason.is_empty(),
10144            "VersaoInvalid `reason` must carry the parser's wording verbatim"
10145        );
10146    }
10147
10148    #[test]
10149    fn validate_versao_accepts_what_upgrade_from_from_accepts() {
10150        // Parity pin: every shape `UpgradeFromEntry::validate` accepts
10151        // for `:upgrade-from :from` must also pass `validate_versao` —
10152        // the two `:versao`-typed surfaces (top-level `:versao`,
10153        // `:upgrade-from :from`) consume the *same* `semver::Version`
10154        // parser, so they must agree on the accepted set. Without this
10155        // pin, a future tightening of one axis could silently diverge
10156        // from the other. Mirrors the `:versao` requirement-axis
10157        // parity (`:deps`/`:deps-dev`/`:membros`/`:children`) the prior
10158        // commits established.
10159        for versao in ["0.1.0", "0.2.0-rc.1", "1.0.0+build.42"] {
10160            // From the canonical UpgradeFromEntry round-trip fixture
10161            // (`upgrade::tests::round_trip_load_module` peers).
10162            let entry = crate::UpgradeFromEntry {
10163                from: versao.to_string(),
10164                instructions: Vec::new(),
10165            };
10166            entry
10167                .validate()
10168                .unwrap_or_else(|e| panic!(":from {versao:?} must validate, got {e:?}"));
10169            caixa_with_versao(versao)
10170                .validate_versao()
10171                .unwrap_or_else(|e| {
10172                    panic!(":versao {versao:?} must validate, got {e:?} — peer axis diverges")
10173                });
10174        }
10175    }
10176
10177    // ── Caixa::validate_restart_window — supervisor restart-window
10178    //    folds through the shared `supervisor::duration_codec` ────────
10179
10180    fn caixa_with_restart_window(window: Option<&str>) -> Caixa {
10181        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
10182        c.kind = CaixaKind::Supervisor;
10183        c.restart_window = window.map(str::to_string);
10184        c
10185    }
10186
10187    #[test]
10188    fn validate_restart_window_accepts_none() {
10189        // The canonical "omit the slot to express no reset" shape — a
10190        // `None` raw string is the absence of the typed
10191        // `:restart-window` slot, which is exactly the SupervisorSpec
10192        // "never reset" semantics. The gate must be a no-op here; a
10193        // future tightening that rejected `None` would force every
10194        // supervisor caixa to authoring-time pin a window even when
10195        // the OTP semantics call for none.
10196        caixa_with_restart_window(None)
10197            .validate_restart_window()
10198            .unwrap();
10199    }
10200
10201    #[test]
10202    fn validate_restart_window_accepts_canonical_forms() {
10203        // Positive-set sweep across the canonical authoring units the
10204        // shared `supervisor::duration_codec::parse` accepts —
10205        // matches the codec-side `parse_accepts_integer_canonical_units`
10206        // pin in supervisor::tests so a future codec-side tightening
10207        // surfaces simultaneously on both axes.
10208        for window in ["60s", "5m", "1h", "500ms", "30", "0s"] {
10209            caixa_with_restart_window(Some(window))
10210                .validate_restart_window()
10211                .unwrap_or_else(|e| {
10212                    panic!("canonical :restart-window {window:?} must validate, got {e:?}")
10213                });
10214        }
10215    }
10216
10217    #[test]
10218    fn validate_restart_window_rejects_fractional_seconds() {
10219        // Fail-before-pass-after pin: the `"1.5s"` drift class (parses
10220        // as f64 to 1.5 → renders back as `"1500ms"` on first
10221        // serialize). Prior to the fold + this gate, the inline
10222        // `parse_window_inline` accepted f64 magnitudes and silently
10223        // produced a `Duration::from_secs_f64(1.5)`, divergent from
10224        // the shared codec's integer-magnitude discipline on the
10225        // serde-routed siblings. The gate now surfaces a self-locating
10226        // diagnostic at the manifest layer.
10227        let err = caixa_with_restart_window(Some("1.5s"))
10228            .validate_restart_window()
10229            .unwrap_err();
10230        let ManifestError::RestartWindowMalformed {
10231            restart_window,
10232            reason,
10233        } = err
10234        else {
10235            panic!("expected RestartWindowMalformed for fractional seconds");
10236        };
10237        assert_eq!(restart_window, "1.5s");
10238        assert!(
10239            reason.contains("\"1.5\"") && reason.contains("not a non-negative integer"),
10240            "diagnostic must carry shared-codec wording, got {reason:?}"
10241        );
10242    }
10243
10244    #[test]
10245    fn validate_restart_window_rejects_decimal_shaped_integer() {
10246        // The `"1.0s"` class — numerically `1s` exactly, but the
10247        // canonical form is `"1s"` not `"1.0s"`. Decimal-shape leak
10248        // gets the same canonical-form diagnostic.
10249        let err = caixa_with_restart_window(Some("1.0s"))
10250            .validate_restart_window()
10251            .unwrap_err();
10252        assert!(
10253            matches!(
10254                err,
10255                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10256                    if restart_window == "1.0s"
10257            ),
10258            "got {err:?}"
10259        );
10260    }
10261
10262    #[test]
10263    fn validate_restart_window_rejects_half_unit_minute() {
10264        // `"0.5m"` is the unit-fraction footgun — author writes a
10265        // human-readable half-minute, the prior inline parser silently
10266        // produced `Duration::from_secs_f64(30.0)` and serde
10267        // re-emitted as `"30s"`, rewriting author intent. The gate
10268        // closes the loop at the manifest layer.
10269        let err = caixa_with_restart_window(Some("0.5m"))
10270            .validate_restart_window()
10271            .unwrap_err();
10272        let ManifestError::RestartWindowMalformed {
10273            restart_window,
10274            reason,
10275        } = err
10276        else {
10277            panic!("expected RestartWindowMalformed");
10278        };
10279        assert_eq!(restart_window, "0.5m");
10280        assert!(
10281            reason.contains("\"30s\""),
10282            "diagnostic must point at the canonical-form remediation, got {reason:?}"
10283        );
10284    }
10285
10286    #[test]
10287    fn validate_restart_window_rejects_leading_sign() {
10288        // `"+30s"` and `"-30s"` both round-tripped through f64 cleanly
10289        // on the prior parser (`+30` parses as `30.0`; `-30` parsed
10290        // and was caught by the `num < 0.0` arm which silently
10291        // returned `None`, dropping the author-supplied window). The
10292        // shared codec's digit-only gate rejects both with a unified
10293        // canonical-form diagnostic; the manifest-layer wrapper names
10294        // the offending value.
10295        for bad in ["+30s", "-30s"] {
10296            let err = caixa_with_restart_window(Some(bad))
10297                .validate_restart_window()
10298                .unwrap_err();
10299            assert!(
10300                matches!(
10301                    err,
10302                    ManifestError::RestartWindowMalformed { ref restart_window, .. }
10303                        if restart_window == bad
10304                ),
10305                "got {err:?} for {bad:?}"
10306            );
10307        }
10308    }
10309
10310    #[test]
10311    fn validate_restart_window_rejects_unknown_unit() {
10312        // `"30x"` — the typo / wrong-unit footgun. The shared codec's
10313        // unit dispatch surfaces an `unknown duration unit` reason;
10314        // the manifest-layer wrapper names the offending value.
10315        let err = caixa_with_restart_window(Some("30x"))
10316            .validate_restart_window()
10317            .unwrap_err();
10318        let ManifestError::RestartWindowMalformed {
10319            restart_window,
10320            reason,
10321        } = err
10322        else {
10323            panic!("expected RestartWindowMalformed for unknown unit");
10324        };
10325        assert_eq!(restart_window, "30x");
10326        assert!(
10327            reason.contains("unknown duration unit"),
10328            "diagnostic must carry shared-codec unit-rejection wording, got {reason:?}"
10329        );
10330    }
10331
10332    #[test]
10333    fn validate_restart_window_rejects_garbage() {
10334        // Pure non-numeric magnitude (`"abc"`) falls through to the
10335        // shared codec's narrower `"bad duration magnitude"` arm. Same
10336        // diagnostic shape as the codec-side
10337        // `parse_garbage_still_falls_through_to_bad_magnitude` pin.
10338        let err = caixa_with_restart_window(Some("abc"))
10339            .validate_restart_window()
10340            .unwrap_err();
10341        let ManifestError::RestartWindowMalformed {
10342            restart_window,
10343            reason,
10344        } = err
10345        else {
10346            panic!("expected RestartWindowMalformed for garbage");
10347        };
10348        assert_eq!(restart_window, "abc");
10349        assert!(
10350            reason.contains("bad duration magnitude"),
10351            "diagnostic must carry shared-codec garbage-rejection wording, got {reason:?}"
10352        );
10353    }
10354
10355    #[test]
10356    fn validate_restart_window_rejects_empty_string() {
10357        // The empty-after-trim edge case — distinct from the `None`
10358        // canonical "omit the slot" shape. The shared codec's
10359        // digit-only gate refuses an empty magnitude; the manifest
10360        // layer names the offending `""` so the author can grep for
10361        // the literal empty value in their `caixa.lisp` and either
10362        // remove the slot (the canonical "no reset" shape) or pin a
10363        // positive duration.
10364        let err = caixa_with_restart_window(Some(""))
10365            .validate_restart_window()
10366            .unwrap_err();
10367        assert!(
10368            matches!(
10369                err,
10370                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10371                    if restart_window.is_empty()
10372            ),
10373            "got {err:?}"
10374        );
10375    }
10376
10377    #[test]
10378    fn validate_restart_window_diagnostic_carries_offending_value() {
10379        // Diagnostic-shape pin (peer with
10380        // `nome_invalid_diagnostic_carries_offending_nome` /
10381        // `versao_invalid_diagnostic_carries_offending_versao`): the
10382        // error names the offending raw `:restart-window` verbatim
10383        // with a non-empty shared-codec-shaped reason, so a `feira
10384        // lint` run can render the diagnostic without re-parsing.
10385        let err = caixa_with_restart_window(Some("1.5s"))
10386            .validate_restart_window()
10387            .unwrap_err();
10388        let ManifestError::RestartWindowMalformed {
10389            restart_window,
10390            reason,
10391        } = err
10392        else {
10393            panic!("expected RestartWindowMalformed variant");
10394        };
10395        assert_eq!(restart_window, "1.5s");
10396        assert!(
10397            !reason.is_empty(),
10398            "RestartWindowMalformed `reason` must carry the codec's wording verbatim"
10399        );
10400    }
10401
10402    #[test]
10403    fn supervisor_view_folds_through_shared_codec_on_canonical_form() {
10404        // Behavioral parity pin after the fold (`parse_window_inline`
10405        // deletion): the canonical `"60s"` still produces
10406        // `Duration::from_secs(60)` on the typed view — the fold is
10407        // semantically equivalent to the prior inline parser on the
10408        // accepted set. Mirrors the pre-fold `supervisor_view_returns_typed_shape`
10409        // pin, narrowed to the parser-side contract.
10410        let c = caixa_with_restart_window(Some("60s"));
10411        let view = c.supervisor_view().expect("Supervisor kind has a view");
10412        assert_eq!(
10413            view.restart_window,
10414            Some(std::time::Duration::from_secs(60))
10415        );
10416    }
10417
10418    #[test]
10419    fn supervisor_view_soft_swallows_what_validate_rejects() {
10420        // Parity pin between the view-construction path and the
10421        // manifest-level validator: the same `"1.5s"` that surfaces
10422        // `RestartWindowMalformed` at `validate_restart_window` time
10423        // becomes `restart_window: None` on the typed view (the fold
10424        // preserves the existing best-effort shape of `supervisor_view`).
10425        // The contract is: a layout-verifier / `feira lint` flow that
10426        // cares about the malformed-window axis MUST consult
10427        // `validate_restart_window` — relying solely on the view's
10428        // `None` swallows the diagnostic silently. This pin makes the
10429        // expectation a typed invariant.
10430        let c = caixa_with_restart_window(Some("1.5s"));
10431        let view = c.supervisor_view().expect("Supervisor kind has a view");
10432        assert_eq!(
10433            view.restart_window, None,
10434            "view-construction path soft-swallows the parse error to None"
10435        );
10436        // And the manifest-level validator does NOT soft-swallow:
10437        assert!(
10438            matches!(
10439                c.validate_restart_window().unwrap_err(),
10440                ManifestError::RestartWindowMalformed { ref restart_window, .. }
10441                    if restart_window == "1.5s"
10442            ),
10443            "validator must surface the offending value",
10444        );
10445    }
10446
10447    // ── validate_code_paths — per-entry shape on :bibliotecas / :exe / :servicos ──
10448
10449    fn caixa_with_code_paths(bibliotecas: Vec<&str>, exe: Vec<&str>, servicos: Vec<&str>) -> Caixa {
10450        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10451        c.bibliotecas = bibliotecas.into_iter().map(String::from).collect();
10452        c.exe = exe.into_iter().map(String::from).collect();
10453        c.servicos = servicos.into_iter().map(String::from).collect();
10454        c
10455    }
10456
10457    #[test]
10458    fn validate_code_paths_accepts_canonical_template() {
10459        // The bare `Caixa::template` shape is the gate's identity element
10460        // on the canonical authoring shape — `:bibliotecas
10461        // ("lib/demo.lisp")` + empty `:exe` + empty `:servicos`. Pins
10462        // that the gate is non-disruptive against every existing caixa.
10463        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
10464        c.validate_code_paths().unwrap();
10465    }
10466
10467    #[test]
10468    fn validate_code_paths_accepts_explicit_relative_paths_on_every_slot() {
10469        // Positive control sweep: a canonical-shaped path on every slot
10470        // passes. Mirrors the peer
10471        // `behavior::validate_every_slot_relative_is_ok` pin.
10472        let c = caixa_with_code_paths(
10473            vec!["lib/demo.lisp", "lib/helpers.lisp"],
10474            vec!["exe/demo", "exe/tool"],
10475            vec!["servicos/demo.computeunit.yaml"],
10476        );
10477        c.validate_code_paths().unwrap();
10478    }
10479
10480    #[test]
10481    fn validate_code_paths_accepts_all_empty_lists() {
10482        // The empty-list identity element: every Caixa with no declared
10483        // code paths trivially passes (Supervisor / Aplicacao kinds rely
10484        // on this — the OwnCode gate already rejected them before the
10485        // path-shape gate runs in the layout, but the validator itself
10486        // must accept the empty shape).
10487        let c = caixa_with_code_paths(vec![], vec![], vec![]);
10488        c.validate_code_paths().unwrap();
10489    }
10490
10491    #[test]
10492    fn validate_code_paths_rejects_empty_bibliotecas_entry() {
10493        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
10494        let err = c.validate_code_paths().unwrap_err();
10495        assert!(
10496            matches!(
10497                err,
10498                ManifestError::CodePathEmpty {
10499                    slot: ":bibliotecas"
10500                }
10501            ),
10502            "got {err:?}",
10503        );
10504    }
10505
10506    #[test]
10507    fn validate_code_paths_rejects_empty_exe_entry() {
10508        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
10509        let err = c.validate_code_paths().unwrap_err();
10510        assert!(
10511            matches!(err, ManifestError::CodePathEmpty { slot: ":exe" }),
10512            "got {err:?}",
10513        );
10514    }
10515
10516    #[test]
10517    fn validate_code_paths_rejects_empty_servicos_entry() {
10518        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
10519        let err = c.validate_code_paths().unwrap_err();
10520        assert!(
10521            matches!(err, ManifestError::CodePathEmpty { slot: ":servicos" }),
10522            "got {err:?}",
10523        );
10524    }
10525
10526    #[test]
10527    fn validate_code_paths_rejects_absolute_bibliotecas_entry() {
10528        // `:bibliotecas` has no `starts_with(<dir>)` fence downstream,
10529        // so an absolute path that resolves on disk silently passes the
10530        // layout's existence check — the canonical sandbox-escape on
10531        // the biblioteca axis.
10532        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10533        let err = c.validate_code_paths().unwrap_err();
10534        let ManifestError::CodePathAbsolute { slot, path } = err else {
10535            panic!("expected CodePathAbsolute, got {err:?}");
10536        };
10537        assert_eq!(slot, ":bibliotecas");
10538        assert_eq!(path, PathBuf::from("/etc/passwd"));
10539    }
10540
10541    #[test]
10542    fn validate_code_paths_rejects_absolute_exe_entry() {
10543        let c = caixa_with_code_paths(vec![], vec!["/usr/bin/env"], vec![]);
10544        let err = c.validate_code_paths().unwrap_err();
10545        let ManifestError::CodePathAbsolute { slot, path } = err else {
10546            panic!("expected CodePathAbsolute, got {err:?}");
10547        };
10548        assert_eq!(slot, ":exe");
10549        assert_eq!(path, PathBuf::from("/usr/bin/env"));
10550    }
10551
10552    #[test]
10553    fn validate_code_paths_rejects_absolute_servicos_entry() {
10554        let c = caixa_with_code_paths(vec![], vec![], vec!["/var/servicos/x.yaml"]);
10555        let err = c.validate_code_paths().unwrap_err();
10556        let ManifestError::CodePathAbsolute { slot, path } = err else {
10557            panic!("expected CodePathAbsolute, got {err:?}");
10558        };
10559        assert_eq!(slot, ":servicos");
10560        assert_eq!(path, PathBuf::from("/var/servicos/x.yaml"));
10561    }
10562
10563    #[test]
10564    fn validate_code_paths_rejects_parent_escape_bibliotecas_leading() {
10565        // Canonical "I want a lib from a sibling caixa" footgun on the
10566        // biblioteca axis. `:bibliotecas` has no `starts_with` fence
10567        // downstream, so a leading `..` traverses to the parent of the
10568        // caixa root with no diagnostic at layout time if the resolved
10569        // target exists.
10570        let c = caixa_with_code_paths(vec!["../sibling/x.lisp"], vec![], vec![]);
10571        let err = c.validate_code_paths().unwrap_err();
10572        let ManifestError::CodePathParentEscape { slot, path } = err else {
10573            panic!("expected CodePathParentEscape, got {err:?}");
10574        };
10575        assert_eq!(slot, ":bibliotecas");
10576        assert_eq!(path, PathBuf::from("../sibling/x.lisp"));
10577    }
10578
10579    #[test]
10580    fn validate_code_paths_rejects_parent_escape_exe_mid_path() {
10581        // Mid-path `..` defeats the layout's component-aware
10582        // `starts_with(exe_dir)` fence — `root.join("exe/../../escape")`
10583        // `starts_with(<root>/exe)` is true, but the canonical resolution
10584        // lives outside the caixa root. Caught regardless of where the
10585        // `..` sits — mirrors the peer
10586        // `behavior::validate_rejects_parent_escape_mid_path` pin.
10587        let c = caixa_with_code_paths(vec![], vec!["exe/../../escape"], vec![]);
10588        let err = c.validate_code_paths().unwrap_err();
10589        let ManifestError::CodePathParentEscape { slot, path } = err else {
10590            panic!("expected CodePathParentEscape, got {err:?}");
10591        };
10592        assert_eq!(slot, ":exe");
10593        assert_eq!(path, PathBuf::from("exe/../../escape"));
10594    }
10595
10596    #[test]
10597    fn validate_code_paths_rejects_parent_escape_servicos_trailing() {
10598        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/foo/../../escape.yaml"]);
10599        let err = c.validate_code_paths().unwrap_err();
10600        let ManifestError::CodePathParentEscape { slot, path } = err else {
10601            panic!("expected CodePathParentEscape, got {err:?}");
10602        };
10603        assert_eq!(slot, ":servicos");
10604        assert_eq!(path, PathBuf::from("servicos/foo/../../escape.yaml"));
10605    }
10606
10607    #[test]
10608    fn validate_code_paths_cross_slot_precedence_bibliotecas_before_exe_before_servicos() {
10609        // Cross-slot precedence pin: `:bibliotecas` → `:exe` →
10610        // `:servicos`. A manifest with malformed entries on all three
10611        // surfaces surfaces the `:bibliotecas` defect first, mirroring
10612        // the canonical declaration order
10613        // `Caixa::declared_foreign_code_slots` already establishes for
10614        // the foreign-code-slot diagnostic.
10615        let c = caixa_with_code_paths(vec![""], vec![""], vec![""]);
10616        let err = c.validate_code_paths().unwrap_err();
10617        assert!(
10618            matches!(
10619                err,
10620                ManifestError::CodePathEmpty {
10621                    slot: ":bibliotecas"
10622                }
10623            ),
10624            "got {err:?}",
10625        );
10626    }
10627
10628    #[test]
10629    fn validate_code_paths_within_slot_precedence_empty_before_absolute_before_parent_escape() {
10630        // Within-slot precedence pin: empty → absolute → parent-escape,
10631        // matching the [`PathShapeViolation`] arm-ordering every peer
10632        // `is_sandboxed_relative_path` caller follows (b0c8389
10633        // BehaviorSpec, 26da2c7 UpgradeInstruction::StateChange). A
10634        // `:bibliotecas` list whose first entry is empty *and* whose
10635        // later entries are absolute/parent-escape surfaces the empty
10636        // arm first, on the lexicographically-earliest offending entry.
10637        let c = caixa_with_code_paths(vec!["", "/etc/passwd", "../escape.lisp"], vec![], vec![]);
10638        let err = c.validate_code_paths().unwrap_err();
10639        assert!(
10640            matches!(
10641                err,
10642                ManifestError::CodePathEmpty {
10643                    slot: ":bibliotecas"
10644                }
10645            ),
10646            "got {err:?}",
10647        );
10648    }
10649
10650    #[test]
10651    fn validate_code_paths_first_offender_per_slot_wins() {
10652        // Within a single slot, the first declaration-order offender
10653        // surfaces — pins that the gate is left-to-right deterministic
10654        // (peer of every `*_first_collision_*` pin on duplicate gates).
10655        let c = caixa_with_code_paths(
10656            vec!["lib/ok.lisp", "/etc/escape", "../also-escape"],
10657            vec![],
10658            vec![],
10659        );
10660        let err = c.validate_code_paths().unwrap_err();
10661        let ManifestError::CodePathAbsolute { slot, path } = err else {
10662            panic!("expected CodePathAbsolute, got {err:?}");
10663        };
10664        assert_eq!(slot, ":bibliotecas");
10665        assert_eq!(path, PathBuf::from("/etc/escape"));
10666    }
10667
10668    #[test]
10669    fn validate_code_paths_diagnostic_carries_offending_slot_and_path() {
10670        // Diagnostic-shape pin (peer with
10671        // `nome_invalid_diagnostic_carries_offending_nome` /
10672        // `versao_invalid_diagnostic_carries_offending_versao`): the
10673        // error's Display surfaces both the offending `:slot` tag and
10674        // the offending path verbatim, so a `feira lint` run can render
10675        // the diagnostic without re-parsing.
10676        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10677        let rendered = c.validate_code_paths().unwrap_err().to_string();
10678        assert!(
10679            rendered.contains(":bibliotecas"),
10680            "diagnostic must name the offending slot: {rendered}",
10681        );
10682        assert!(
10683            rendered.contains("/etc/passwd"),
10684            "diagnostic must quote the offending path: {rendered}",
10685        );
10686    }
10687
10688    #[test]
10689    fn validate_code_paths_rejects_duplicate_bibliotecas_entry() {
10690        // Canonical copy-paste-the-wrong-file footgun on the biblioteca
10691        // axis. Without the gate `feira build` re-parses the same lib
10692        // twice, wasting work and silently masking the author's intent
10693        // to declare a *second* biblioteca.
10694        let c = caixa_with_code_paths(vec!["lib/demo.lisp", "lib/demo.lisp"], vec![], vec![]);
10695        let err = c.validate_code_paths().unwrap_err();
10696        let ManifestError::CodePathDuplicate { slot, path } = err else {
10697            panic!("expected CodePathDuplicate, got {err:?}");
10698        };
10699        assert_eq!(slot, ":bibliotecas");
10700        assert_eq!(path, PathBuf::from("lib/demo.lisp"));
10701    }
10702
10703    #[test]
10704    fn validate_code_paths_rejects_duplicate_exe_entry() {
10705        // Same footgun on the Binario surface. The future `caixa-flake`
10706        // emitter that materializes each `:exe` entry as a flake
10707        // `packages.<name>` derivation would collide on the duplicate
10708        // package key — surfaced here at the typed-validate layer with a
10709        // self-locating diagnostic instead.
10710        let c = caixa_with_code_paths(vec![], vec!["exe/cli", "exe/cli"], vec![]);
10711        let err = c.validate_code_paths().unwrap_err();
10712        let ManifestError::CodePathDuplicate { slot, path } = err else {
10713            panic!("expected CodePathDuplicate, got {err:?}");
10714        };
10715        assert_eq!(slot, ":exe");
10716        assert_eq!(path, PathBuf::from("exe/cli"));
10717    }
10718
10719    #[test]
10720    fn validate_code_paths_rejects_duplicate_servicos_entry() {
10721        // Same footgun on the Servico surface. The peer caixa-helm /
10722        // caixa-flux renderers refuse `:servicos.len() != 1` with the
10723        // narrower `UnsupportedServicoCount` diagnostic, but that
10724        // diagnostic surfaces "too many servicos" without naming
10725        // "duplicate entry" — the typed self-locating framing only lands
10726        // at this gate.
10727        let c = caixa_with_code_paths(
10728            vec![],
10729            vec![],
10730            vec![
10731                "servicos/demo.computeunit.yaml",
10732                "servicos/demo.computeunit.yaml",
10733            ],
10734        );
10735        let err = c.validate_code_paths().unwrap_err();
10736        let ManifestError::CodePathDuplicate { slot, path } = err else {
10737            panic!("expected CodePathDuplicate, got {err:?}");
10738        };
10739        assert_eq!(slot, ":servicos");
10740        assert_eq!(path, PathBuf::from("servicos/demo.computeunit.yaml"));
10741    }
10742
10743    #[test]
10744    fn validate_code_paths_accepts_same_path_across_slots() {
10745        // Per-list scope pin: a `:bibliotecas` entry that happens to
10746        // collide with an `:exe` or `:servicos` entry as a *string* is
10747        // not a duplicate by this gate (each list gets its own HashSet),
10748        // mirroring the peer `:deps` ↔ `:deps-dev` per-list scope
10749        // (a `:nome` present in both lists is a legitimate dev-vs-runtime
10750        // shape on the dep axis). The structural `starts_with(<exe |
10751        // servicos>_dir)` fence at layout time prevents the realistic
10752        // cross-slot collision case from existing on disk, but the gate's
10753        // per-list scope is correct independent of that downstream fence.
10754        let c = caixa_with_code_paths(
10755            vec!["lib/x.lisp"],
10756            vec!["exe/x"],
10757            vec!["servicos/x.computeunit.yaml"],
10758        );
10759        c.validate_code_paths().unwrap();
10760    }
10761
10762    #[test]
10763    fn validate_code_paths_duplicate_fires_after_structural_checks_on_same_slot() {
10764        // Within-slot ordering pin: structural defects (empty / absolute
10765        // / parent-escape) fire before the duplicate gate on the same
10766        // slot. A `:bibliotecas ("" "lib/x.lisp" "lib/x.lisp")` shape
10767        // surfaces the narrower `CodePathEmpty` for the empty entry
10768        // first, not the duplicate on the later pair — same arm-ordering
10769        // every peer per-list duplicate gate uses (`:etiquetas` 360a499,
10770        // `:autores` 86c769b, `:deps` 359fba5).
10771        let c = caixa_with_code_paths(vec!["", "lib/x.lisp", "lib/x.lisp"], vec![], vec![]);
10772        let err = c.validate_code_paths().unwrap_err();
10773        assert!(
10774            matches!(
10775                err,
10776                ManifestError::CodePathEmpty {
10777                    slot: ":bibliotecas"
10778                }
10779            ),
10780            "got {err:?}",
10781        );
10782    }
10783
10784    #[test]
10785    fn validate_code_paths_duplicate_in_bibliotecas_fires_before_duplicate_in_exe() {
10786        // Cross-slot ordering pin on the duplicate arm: `:bibliotecas`
10787        // duplicates surface before `:exe` duplicates, matching the
10788        // canonical `:bibliotecas` → `:exe` → `:servicos` declaration
10789        // order every peer per-slot diagnostic on this surface follows.
10790        let c = caixa_with_code_paths(
10791            vec!["lib/x.lisp", "lib/x.lisp"],
10792            vec!["exe/y", "exe/y"],
10793            vec![],
10794        );
10795        let err = c.validate_code_paths().unwrap_err();
10796        let ManifestError::CodePathDuplicate { slot, path } = err else {
10797            panic!("expected CodePathDuplicate, got {err:?}");
10798        };
10799        assert_eq!(slot, ":bibliotecas");
10800        assert_eq!(path, PathBuf::from("lib/x.lisp"));
10801    }
10802
10803    #[test]
10804    fn validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path() {
10805        // Diagnostic-shape pin (peer with
10806        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
10807        // on the structural arm): the duplicate-arm Display surfaces both
10808        // the offending `:slot` tag and the offending path verbatim, so a
10809        // `feira lint` run can render the diagnostic without re-parsing.
10810        let c = caixa_with_code_paths(
10811            vec![],
10812            vec![],
10813            vec![
10814                "servicos/demo.computeunit.yaml",
10815                "servicos/demo.computeunit.yaml",
10816            ],
10817        );
10818        let rendered = c.validate_code_paths().unwrap_err().to_string();
10819        assert!(
10820            rendered.contains(":servicos"),
10821            "diagnostic must name the offending slot: {rendered}",
10822        );
10823        assert!(
10824            rendered.contains("servicos/demo.computeunit.yaml"),
10825            "diagnostic must quote the offending path: {rendered}",
10826        );
10827    }
10828
10829    // ── validate_code_paths — `.lisp` extension gate on :bibliotecas ──
10830    //
10831    // The lifted [`crate::render::is_lisp_extension`] predicate (33cc830)
10832    // now gates `:bibliotecas` entries on the tatara-lisp-source file-type
10833    // contract. The `feira build` loop (`caixa-feira/src/cmd/build.rs:33`)
10834    // reads every declared `:bibliotecas` entry through `tatara_lisp::read`
10835    // at parse time — the same downstream consumer the peer `:behavior
10836    // :on-*` (c97815a, [`crate::BehaviorError::NonLispExtension`]) and
10837    // `:upgrade-from :state-change :script` (33cc830,
10838    // [`crate::UpgradeError::NonLispExtensionScript`]) axes route through.
10839    // `:exe` and `:servicos` are deliberately excluded — `:exe` is the
10840    // nix-built executable surface (`"exe/<name>"` shape per the canonical
10841    // [`crate::LayoutError::ExeOutsideDir`] error message and every
10842    // in-tree `caixa_with_code_paths` positive control), and `:servicos`
10843    // is the `.computeunit.yaml` ComputeUnit-CR axis.
10844
10845    #[test]
10846    fn validate_code_paths_rejects_no_extension_bibliotecas_entry() {
10847        // Canonical "I dragged the wrong file from the workspace tree"
10848        // footgun on the biblioteca axis. Without the gate `feira build`
10849        // hands the extensionless path to `tatara_lisp::read` and fails
10850        // with a parser-shaped diagnostic far from the source caixa.lisp,
10851        // with no field naming the offending `:bibliotecas` entry.
10852        for relpath in ["lib/demo", "demo", "lib/handlers/inner"] {
10853            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10854            let err = c.validate_code_paths().unwrap_err();
10855            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10856                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10857            };
10858            assert_eq!(slot, ":bibliotecas");
10859            assert_eq!(path, PathBuf::from(relpath));
10860        }
10861    }
10862
10863    #[test]
10864    fn validate_code_paths_rejects_wrong_extension_bibliotecas_entry() {
10865        // Wrong-extension sweep across common authoring footguns. Same
10866        // sweep posture as the peer
10867        // `behavior::validate_rejects_wrong_extension` (c97815a) and
10868        // `upgrade::tests::state_change_rejects_wrong_extension_script`
10869        // (33cc830) cases.
10870        for relpath in [
10871            "lib/demo.rs",
10872            "lib/demo.txt",
10873            "lib/demo.md",
10874            "lib/demo.json",
10875            "lib/demo.yaml",
10876            "lib/demo.toml",
10877            "lib/demo.lisp.bak",
10878            "lib/demo.lispx",
10879            "lib/demo.lis",
10880        ] {
10881            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10882            let err = c.validate_code_paths().unwrap_err();
10883            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10884                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10885            };
10886            assert_eq!(slot, ":bibliotecas");
10887            assert_eq!(path, PathBuf::from(relpath));
10888        }
10889    }
10890
10891    #[test]
10892    fn validate_code_paths_rejects_case_folded_extension_bibliotecas_entry() {
10893        // Case-sensitivity sweep — pins the strict lowercase `.lisp`
10894        // contract. An uppercase `.LISP` shape that the layout's existence
10895        // check would (case-insensitively, on case-insensitive volumes)
10896        // match the on-disk file still mismatches the canonical form the
10897        // codec emits, breaking the THEORY.md §V.2.7 render-determinism
10898        // contract. Mirrors the peer
10899        // `behavior::validate_rejects_case_folded_extension` (c97815a) and
10900        // `upgrade::tests::state_change_rejects_case_folded_extension_script`
10901        // (33cc830) sweeps.
10902        for relpath in [
10903            "lib/demo.LISP",
10904            "lib/demo.Lisp",
10905            "lib/demo.LiSp",
10906            "lib/demo.lISP",
10907        ] {
10908            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10909            let err = c.validate_code_paths().unwrap_err();
10910            let ManifestError::CodePathNonLispExtension { slot, path } = err else {
10911                panic!("expected CodePathNonLispExtension for {relpath:?}, got {err:?}");
10912            };
10913            assert_eq!(slot, ":bibliotecas");
10914            assert_eq!(path, PathBuf::from(relpath));
10915        }
10916    }
10917
10918    #[test]
10919    fn validate_code_paths_accepts_canonical_lisp_shapes() {
10920        // Positive-control sweep through every canonical authoring shape
10921        // every in-tree fixture and the `Caixa::template` scaffold use.
10922        // Mirrors the peer `behavior::validate_accepts_canonical_lisp_paths`
10923        // (c97815a) and the lifted predicate's own
10924        // `is_lisp_extension_accepts_canonical_shapes` sweep in render.rs
10925        // (33cc830).
10926        for relpath in [
10927            "lib/demo.lisp",
10928            "lib/handlers.lisp",
10929            "lib/migrations/v01-to-v02.lisp",
10930            "demo.lisp",
10931            "a.lisp",
10932            "./lib/demo.lisp",
10933            "lib/./handlers.lisp",
10934            "lib/migrations/v.0.1.lisp",
10935        ] {
10936            let c = caixa_with_code_paths(vec![relpath], vec![], vec![]);
10937            c.validate_code_paths()
10938                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
10939        }
10940    }
10941
10942    #[test]
10943    fn validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos() {
10944        // The file-type gate is per-slot — only `:bibliotecas` carries the
10945        // tatara-lisp-source contract. An extensionless `:exe` entry
10946        // (`exe/demo`) and a `.computeunit.yaml` `:servicos` entry are the
10947        // canonical shapes every in-tree fixture uses, and must continue
10948        // to pass validate. Pins that a future tightening that broadens
10949        // the `.lisp` gate to either axis surfaces as a test failure
10950        // rather than as a silent breaking change to existing valid
10951        // manifests.
10952        let c = caixa_with_code_paths(
10953            vec![],
10954            vec!["exe/demo", "exe/tool"],
10955            vec!["servicos/demo.computeunit.yaml"],
10956        );
10957        c.validate_code_paths().unwrap();
10958    }
10959
10960    #[test]
10961    fn validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension() {
10962        // Cross-arm precedence pin: a `:bibliotecas` entry that is *both*
10963        // sandbox-escaping and non-`.lisp` surfaces the more fundamental
10964        // sandbox-shape diagnostic first (the `.lisp` remediation would
10965        // be misleading when the offending path can never resolve under
10966        // the caixa root anyway). Mirrors the peer
10967        // `EmptyPath` → `AbsolutePath` → `ParentEscape` → `NonLispExtension`
10968        // ordering on `:behavior :on-*` (c97815a) and `EmptyScript` →
10969        // `AbsoluteScript` → `ParentEscapeScript` → `NonLispExtensionScript`
10970        // on `:upgrade-from :state-change :script` (33cc830).
10971        //
10972        // Empty wins (the strictly-smaller-scope structural arm).
10973        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
10974        assert!(
10975            matches!(
10976                c.validate_code_paths().unwrap_err(),
10977                ManifestError::CodePathEmpty {
10978                    slot: ":bibliotecas"
10979                }
10980            ),
10981            "empty must win over non-lisp-extension",
10982        );
10983        // Absolute wins (the path can't resolve under the caixa root).
10984        let c = caixa_with_code_paths(vec!["/etc/passwd"], vec![], vec![]);
10985        let err = c.validate_code_paths().unwrap_err();
10986        let ManifestError::CodePathAbsolute { slot, .. } = err else {
10987            panic!("absolute must win over non-lisp-extension, got {err:?}");
10988        };
10989        assert_eq!(slot, ":bibliotecas");
10990        // ParentEscape wins (the path escapes the caixa root).
10991        let c = caixa_with_code_paths(vec!["../sibling/x.txt"], vec![], vec![]);
10992        let err = c.validate_code_paths().unwrap_err();
10993        let ManifestError::CodePathParentEscape { slot, .. } = err else {
10994            panic!("parent-escape must win over non-lisp-extension, got {err:?}");
10995        };
10996        assert_eq!(slot, ":bibliotecas");
10997    }
10998
10999    #[test]
11000    fn validate_code_paths_non_lisp_extension_precedes_duplicate() {
11001        // Within-slot precedence pin: the per-entry file-type shape gate
11002        // fires before the cross-entry duplicate gate, so the narrower
11003        // structural defect dominates the uniqueness diagnostic. A
11004        // `("lib/x.txt" "lib/x.txt")` shape surfaces
11005        // `CodePathNonLispExtension` on the first entry rather than
11006        // `CodePathDuplicate` on the pair — same posture every per-entry
11007        // shape-gate-precedes-duplicate cascade follows on this surface
11008        // (the empty / absolute / parent-escape arms already precede the
11009        // duplicate arm; the lifted file-type arm joins that set).
11010        let c = caixa_with_code_paths(vec!["lib/x.txt", "lib/x.txt"], vec![], vec![]);
11011        let err = c.validate_code_paths().unwrap_err();
11012        let ManifestError::CodePathNonLispExtension { slot, path } = err else {
11013            panic!("expected CodePathNonLispExtension, got {err:?}");
11014        };
11015        assert_eq!(slot, ":bibliotecas");
11016        assert_eq!(path, PathBuf::from("lib/x.txt"));
11017    }
11018
11019    #[test]
11020    fn validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path() {
11021        // Diagnostic-shape pin (peer with
11022        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`
11023        // on the sandbox-shape arms and
11024        // `validate_code_paths_duplicate_diagnostic_carries_offending_slot_and_path`
11025        // on the duplicate arm): the file-type-arm Display surfaces both
11026        // the offending `:slot` tag, the offending path verbatim, and the
11027        // expected `.lisp` extension named in the remediation text, so a
11028        // `feira lint` run can render the diagnostic without re-parsing.
11029        let c = caixa_with_code_paths(vec!["lib/demo.rs"], vec![], vec![]);
11030        let rendered = c.validate_code_paths().unwrap_err().to_string();
11031        assert!(
11032            rendered.contains(":bibliotecas"),
11033            "diagnostic must name the offending slot: {rendered}",
11034        );
11035        assert!(
11036            rendered.contains("lib/demo.rs"),
11037            "diagnostic must quote the offending path: {rendered}",
11038        );
11039        assert!(
11040            rendered.contains(".lisp"),
11041            "diagnostic must name the expected extension: {rendered}",
11042        );
11043    }
11044
11045    // ── validate_code_paths — `.computeunit.yaml` compound-suffix gate on :servicos ──
11046    //
11047    // The lifted [`crate::render::is_computeunit_yaml_extension`] predicate
11048    // now gates `:servicos` entries on the ComputeUnit-CR YAML file-type
11049    // contract. The peer caixa-helm / caixa-flux renderers consume each
11050    // `:servicos` entry through `serde_yaml::from_str` as a typed
11051    // `ComputeUnit` CR — same downstream-consumer-shape lift as the peer
11052    // `:bibliotecas` `.lisp` gate (64772a9), here on the compound-suffix
11053    // axis `Path::extension` can't express on its own.
11054
11055    #[test]
11056    fn validate_code_paths_rejects_no_extension_servicos_entry() {
11057        // Canonical "I dragged the wrong file from the workspace tree"
11058        // footgun on the Servico axis. Without the gate the peer
11059        // caixa-helm / caixa-flux renderers hand the extensionless path
11060        // to `serde_yaml::from_str` and fail with a parser-shaped
11061        // diagnostic far from the source caixa.lisp, with no field
11062        // naming the offending `:servicos` entry.
11063        for relpath in ["servicos/demo", "demo", "servicos/sub/nested"] {
11064            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11065            let err = c.validate_code_paths().unwrap_err();
11066            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11067                panic!(
11068                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11069                     got {err:?}"
11070                );
11071            };
11072            assert_eq!(slot, ":servicos");
11073            assert_eq!(path, PathBuf::from(relpath));
11074        }
11075    }
11076
11077    #[test]
11078    fn validate_code_paths_rejects_wrong_extension_servicos_entry() {
11079        // Wrong-extension sweep across common authoring footguns on the
11080        // Servico axis. Bare `.yaml` is the canonical "I forgot the
11081        // `.computeunit` segment" typo; the off-by-one-segment shapes
11082        // (`.computeunit-yaml` / `.computeunit_yaml`) silently pass the
11083        // bare `Path::extension` view but mismatch the typed compound
11084        // suffix the renderers' `serde_yaml::from_str` consumer demands.
11085        // Same sweep-posture as the peer
11086        // `validate_code_paths_rejects_wrong_extension_bibliotecas_entry`
11087        // (64772a9) on the sibling tatara-lisp-source axis.
11088        for relpath in [
11089            "servicos/demo.yaml",
11090            "servicos/demo.yml",
11091            "servicos/demo.json",
11092            "servicos/demo.toml",
11093            "servicos/demo.txt",
11094            "servicos/demo.computeunit.yaml.bak",
11095            "servicos/demo.computeunit.yam",
11096            "servicos/demo.computeunit",
11097            "servicos/demo-computeunit.yaml",
11098            "servicos/demo_computeunit.yaml",
11099        ] {
11100            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11101            let err = c.validate_code_paths().unwrap_err();
11102            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11103                panic!(
11104                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11105                     got {err:?}"
11106                );
11107            };
11108            assert_eq!(slot, ":servicos");
11109            assert_eq!(path, PathBuf::from(relpath));
11110        }
11111    }
11112
11113    #[test]
11114    fn validate_code_paths_rejects_case_folded_extension_servicos_entry() {
11115        // Case-sensitivity sweep — pins the strict lowercase
11116        // `.computeunit.yaml` contract. A case-folded shape that the
11117        // layout's existence check would (case-insensitively, on
11118        // case-insensitive volumes) match the on-disk file still
11119        // mismatches the canonical form the codec emits, breaking the
11120        // THEORY.md §V.2.7 render-determinism contract. Mirrors the peer
11121        // `validate_code_paths_rejects_case_folded_extension_bibliotecas_entry`
11122        // (64772a9) sweep on the sibling tatara-lisp-source axis.
11123        for relpath in [
11124            "servicos/demo.ComputeUnit.yaml",
11125            "servicos/demo.COMPUTEUNIT.yaml",
11126            "servicos/demo.computeunit.YAML",
11127            "servicos/demo.computeunit.Yaml",
11128            "servicos/demo.COMPUTEUNIT.YAML",
11129        ] {
11130            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11131            let err = c.validate_code_paths().unwrap_err();
11132            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11133                panic!(
11134                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11135                     got {err:?}"
11136                );
11137            };
11138            assert_eq!(slot, ":servicos");
11139            assert_eq!(path, PathBuf::from(relpath));
11140        }
11141    }
11142
11143    #[test]
11144    fn validate_code_paths_rejects_empty_stem_servicos_entry() {
11145        // Degenerate hidden-file shape: a file name exactly equal to the
11146        // suffix (`.computeunit.yaml` — no stem preceding the suffix) is
11147        // the structural "Servico declared with no identity" footgun.
11148        // The substrate identifies each ComputeUnit by the file-stem
11149        // segment that precedes `.computeunit.yaml` (the rendered
11150        // `lareira-<stem>` Helm chart, the per-Servico `metadata.name`,
11151        // the M3 `:contratos` membership lookup), so an empty stem
11152        // leaves the Servico unidentifiable. Pinned at the typed-axis
11153        // level so a future regression that drops the `name.len() >
11154        // SUFFIX.len()` bound at the predicate surfaces here, not
11155        // piecemeal as a `lareira-` chart-name collision at render time.
11156        for relpath in ["servicos/.computeunit.yaml"] {
11157            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11158            let err = c.validate_code_paths().unwrap_err();
11159            let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11160                panic!(
11161                    "expected CodePathNonComputeUnitYamlExtension for {relpath:?}, \
11162                     got {err:?}"
11163                );
11164            };
11165            assert_eq!(slot, ":servicos");
11166            assert_eq!(path, PathBuf::from(relpath));
11167        }
11168    }
11169
11170    #[test]
11171    fn validate_code_paths_accepts_canonical_computeunit_yaml_shapes() {
11172        // Positive-control sweep through every canonical authoring shape
11173        // every in-tree fixture and the `Caixa::template` scaffold use.
11174        // Mirrors the peer
11175        // `validate_code_paths_accepts_canonical_lisp_shapes` (64772a9)
11176        // and the lifted predicate's own
11177        // `computeunit_yaml_extension_accepts_canonical_shapes` sweep in
11178        // render.rs.
11179        for relpath in [
11180            "servicos/demo.computeunit.yaml",
11181            "servicos/hello-rio.computeunit.yaml",
11182            "servicos/my-service.computeunit.yaml",
11183            "servicos/a.computeunit.yaml",
11184            "./servicos/demo.computeunit.yaml",
11185            "servicos/./demo.computeunit.yaml",
11186            "servicos/sub/nested.computeunit.yaml",
11187            "servicos/v0.1.computeunit.yaml",
11188        ] {
11189            let c = caixa_with_code_paths(vec![], vec![], vec![relpath]);
11190            c.validate_code_paths()
11191                .unwrap_or_else(|e| panic!("canonical shape {relpath:?} must pass, got {e:?}"));
11192        }
11193    }
11194
11195    #[test]
11196    fn validate_code_paths_non_computeunit_yaml_extension_does_not_fire_on_bibliotecas_or_exe() {
11197        // The file-type gate is per-slot — only `:servicos` carries the
11198        // ComputeUnit-CR YAML contract. A canonical `.lisp` `:bibliotecas`
11199        // entry and an extensionless `:exe` entry are the canonical
11200        // shapes every in-tree fixture uses, and must continue to pass
11201        // validate. Peer of
11202        // `validate_code_paths_non_lisp_extension_does_not_fire_on_exe_or_servicos`
11203        // (64772a9) — together pin that the typed
11204        // [`CodePathFileType`] dispatch is exhaustively per-slot, with no
11205        // cross-axis leakage in either direction.
11206        let c = caixa_with_code_paths(
11207            vec!["lib/demo.lisp"],
11208            vec!["exe/demo", "exe/tool"],
11209            vec!["servicos/demo.computeunit.yaml"],
11210        );
11211        c.validate_code_paths().unwrap();
11212    }
11213
11214    #[test]
11215    fn validate_code_paths_sandbox_shape_arms_precede_non_computeunit_yaml_extension() {
11216        // Cross-arm precedence pin: a `:servicos` entry that is *both*
11217        // sandbox-escaping and wrong-extension surfaces the more
11218        // fundamental sandbox-shape diagnostic first (the
11219        // `.computeunit.yaml` remediation would be misleading when the
11220        // offending path can never resolve under the caixa root
11221        // anyway). Mirrors the peer
11222        // `validate_code_paths_sandbox_shape_arms_precede_non_lisp_extension`
11223        // (64772a9) ordering on the sibling `:bibliotecas` axis and the
11224        // peer `EmptyPath` → `AbsolutePath` → `ParentEscape` →
11225        // `NonComputeUnitYamlExtension` arm-ordering the dispatch
11226        // table establishes.
11227        //
11228        // Empty wins (the strictly-smaller-scope structural arm).
11229        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
11230        assert!(
11231            matches!(
11232                c.validate_code_paths().unwrap_err(),
11233                ManifestError::CodePathEmpty { slot: ":servicos" }
11234            ),
11235            "empty must win over non-computeunit-yaml-extension",
11236        );
11237        // Absolute wins (the path can't resolve under the caixa root).
11238        let c = caixa_with_code_paths(vec![], vec![], vec!["/etc/foo.yaml"]);
11239        let err = c.validate_code_paths().unwrap_err();
11240        let ManifestError::CodePathAbsolute { slot, .. } = err else {
11241            panic!("absolute must win over non-computeunit-yaml-extension, got {err:?}");
11242        };
11243        assert_eq!(slot, ":servicos");
11244        // ParentEscape wins (the path escapes the caixa root).
11245        let c = caixa_with_code_paths(vec![], vec![], vec!["../sibling/x.yaml"]);
11246        let err = c.validate_code_paths().unwrap_err();
11247        let ManifestError::CodePathParentEscape { slot, .. } = err else {
11248            panic!("parent-escape must win over non-computeunit-yaml-extension, got {err:?}");
11249        };
11250        assert_eq!(slot, ":servicos");
11251    }
11252
11253    #[test]
11254    fn validate_code_paths_non_computeunit_yaml_extension_precedes_duplicate() {
11255        // Within-slot precedence pin: the per-entry file-type shape gate
11256        // fires before the cross-entry duplicate gate, so the narrower
11257        // structural defect dominates the uniqueness diagnostic. A
11258        // `("servicos/x.yaml" "servicos/x.yaml")` shape surfaces
11259        // `CodePathNonComputeUnitYamlExtension` on the first entry
11260        // rather than `CodePathDuplicate` on the pair — same posture
11261        // every per-entry shape-gate-precedes-duplicate cascade follows
11262        // on this surface, peer of the 64772a9 `:bibliotecas`
11263        // `("lib/x.txt" "lib/x.txt")` ordering.
11264        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/x.yaml", "servicos/x.yaml"]);
11265        let err = c.validate_code_paths().unwrap_err();
11266        let ManifestError::CodePathNonComputeUnitYamlExtension { slot, path } = err else {
11267            panic!("expected CodePathNonComputeUnitYamlExtension, got {err:?}");
11268        };
11269        assert_eq!(slot, ":servicos");
11270        assert_eq!(path, PathBuf::from("servicos/x.yaml"));
11271    }
11272
11273    #[test]
11274    fn validate_code_paths_non_computeunit_yaml_extension_diagnostic_carries_offending_slot_and_path()
11275     {
11276        // Diagnostic-shape pin (peer with
11277        // `validate_code_paths_non_lisp_extension_diagnostic_carries_offending_slot_and_path`
11278        // on the sibling tatara-lisp-source axis): the file-type-arm
11279        // Display surfaces both the offending `:slot` tag, the
11280        // offending path verbatim, and the expected
11281        // `.computeunit.yaml` compound suffix named in the remediation
11282        // text, so a `feira lint` run can render the diagnostic without
11283        // re-parsing.
11284        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.yaml"]);
11285        let rendered = c.validate_code_paths().unwrap_err().to_string();
11286        assert!(
11287            rendered.contains(":servicos"),
11288            "diagnostic must name the offending slot: {rendered}",
11289        );
11290        assert!(
11291            rendered.contains("servicos/demo.yaml"),
11292            "diagnostic must quote the offending path: {rendered}",
11293        );
11294        assert!(
11295            rendered.contains(".computeunit.yaml"),
11296            "diagnostic must name the expected compound suffix: {rendered}",
11297        );
11298    }
11299
11300    // ── validate_etiquetas — universal-axis registry-search-tag shape ──
11301
11302    fn caixa_with_etiquetas(etiquetas: Vec<&str>) -> Caixa {
11303        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11304        c.etiquetas = etiquetas.into_iter().map(String::from).collect();
11305        c
11306    }
11307
11308    #[test]
11309    fn validate_etiquetas_accepts_empty_list() {
11310        // The empty-list identity: every caixa with no declared tags
11311        // trivially passes — `Caixa::template` emits `:etiquetas ()`,
11312        // so the gate is non-disruptive against every existing manifest.
11313        let c = caixa_with_etiquetas(vec![]);
11314        c.validate_etiquetas().unwrap();
11315    }
11316
11317    #[test]
11318    fn validate_etiquetas_accepts_canonical_forms() {
11319        // Positive control sweep: a canonical-shaped non-empty distinct
11320        // tag list passes, mirroring the example checkout-aplicacao
11321        // (`:etiquetas ("example" "aplicacao" "mesh" "ecommerce" "demo")`)
11322        // and the hello-rio fixture (`("hello-world" "wasm" "rust")`).
11323        let c = caixa_with_etiquetas(vec!["example", "aplicacao", "mesh", "ecommerce", "demo"]);
11324        c.validate_etiquetas().unwrap();
11325    }
11326
11327    #[test]
11328    fn validate_etiquetas_rejects_empty_entry() {
11329        // Canonical paste-from-blank-doc footgun. Without the gate the
11330        // empty entry rendered as `keywords: [""]` in `Chart.yaml`, a
11331        // no-op tag indexing nothing in the future caixa-registry.
11332        let c = caixa_with_etiquetas(vec![""]);
11333        let err = c.validate_etiquetas().unwrap_err();
11334        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11335    }
11336
11337    #[test]
11338    fn validate_etiquetas_rejects_duplicate_entry() {
11339        // Canonical copy-paste-the-wrong-tag footgun. Without the gate
11340        // the duplicate was silently dedup'd by caixa-helm's BTreeSet
11341        // collect at chart render — a "second wins / one silently
11342        // disappears" shape divergent from every peer typed-graph set
11343        // gate. The duplicate-arm names the offending tag verbatim.
11344        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
11345        let err = c.validate_etiquetas().unwrap_err();
11346        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
11347            panic!("expected EtiquetaDuplicate, got {err:?}");
11348        };
11349        assert_eq!(etiqueta, "demo");
11350    }
11351
11352    #[test]
11353    fn validate_etiquetas_empty_takes_precedence_over_duplicate() {
11354        // Empty-first cascade pin: `("" "demo" "demo")` surfaces
11355        // `EtiquetaEmpty` not `EtiquetaDuplicate` — the narrower
11356        // structural "this entry has no value" defect dominates the
11357        // cross-entry uniqueness diagnostic. Mirrors the peer
11358        // empty-before-duplicate cascades on `:caracteristicas`
11359        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
11360        // fc3b4d5) and `:membros :caixa` (`MembroCaixaEmpty` before
11361        // `MembroDuplicate`).
11362        let c = caixa_with_etiquetas(vec!["", "demo", "demo"]);
11363        let err = c.validate_etiquetas().unwrap_err();
11364        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11365    }
11366
11367    #[test]
11368    fn validate_etiquetas_duplicate_reports_first_collision() {
11369        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
11370        // duplicate (the lexicographically-earliest offending position
11371        // — the second `"a"` at index 2 collides with the first `"a"`
11372        // at index 0), not the later `"b"` collision at index 3,
11373        // peer with every other first-collision diagnostic posture on
11374        // this surface (`validate_load_singularity_reports_first_collision`,
11375        // `validate_cleanup_singularity_reports_first_collision`).
11376        let c = caixa_with_etiquetas(vec!["a", "b", "a", "b"]);
11377        let err = c.validate_etiquetas().unwrap_err();
11378        let ManifestError::EtiquetaDuplicate { etiqueta } = err else {
11379            panic!("expected EtiquetaDuplicate, got {err:?}");
11380        };
11381        assert_eq!(etiqueta, "a");
11382    }
11383
11384    #[test]
11385    fn validate_etiquetas_case_sensitive() {
11386        // Case-sensitivity pin: `("Foo" "foo")` is two distinct entries,
11387        // mirroring the peer `:membros :caixa` / `:children :caixa`
11388        // exact-string-match discipline. The shape gate this routine
11389        // landed (`is_chart_keyword_shape`, Cargo crates.io keyword
11390        // grammar) accepts mixed case — crates.io's keyword rule is
11391        // "case-insensitive" at the index layer but admits mixed case
11392        // at the entry layer (the canonical Helm chart `keywords:`
11393        // shape is lowercase by convention, but the grammar admits
11394        // uppercase). Case-sensitivity at the duplicate-set layer
11395        // remains structural — two distinct strings are two distinct
11396        // entries.
11397        let c = caixa_with_etiquetas(vec!["Foo", "foo"]);
11398        c.validate_etiquetas().unwrap();
11399    }
11400
11401    #[test]
11402    fn validate_etiquetas_diagnostic_carries_offending_tag() {
11403        // Diagnostic-shape pin (peer with
11404        // `validate_code_paths_diagnostic_carries_offending_slot_and_path`):
11405        // the error's Display surfaces the offending tag verbatim, so a
11406        // `feira lint` run can render the diagnostic without re-parsing
11407        // and the author can grep their caixa.lisp for the offending
11408        // value.
11409        let c = caixa_with_etiquetas(vec!["demo", "demo"]);
11410        let rendered = c.validate_etiquetas().unwrap_err().to_string();
11411        assert!(
11412            rendered.contains(":etiquetas"),
11413            "diagnostic must name the offending slot: {rendered}",
11414        );
11415        assert!(
11416            rendered.contains("demo"),
11417            "diagnostic must quote the offending tag: {rendered}",
11418        );
11419    }
11420
11421    #[test]
11422    fn validate_etiquetas_rejects_leading_whitespace_entry() {
11423        // Canonical paste-from-aligned-doc footgun. Without the shape
11424        // gate `" mesh"` silently passed validate and landed as a
11425        // YAML plain-style scalar with leading whitespace in the
11426        // rendered Chart.yaml `keywords:` array — every YAML 1.2
11427        // dumper trims leading whitespace from plain-style scalars,
11428        // so the authored space round-tripped inconsistently back
11429        // through `caixa.lisp`. Mirrors the peer
11430        // `validate_autores_rejects_leading_whitespace_entry`.
11431        let c = caixa_with_etiquetas(vec![" mesh"]);
11432        let err = c.validate_etiquetas().unwrap_err();
11433        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11434            panic!("expected EtiquetaInvalid, got {err:?}");
11435        };
11436        assert_eq!(etiqueta, " mesh");
11437        assert!(reason.contains("whitespace"), "got: {reason}");
11438    }
11439
11440    #[test]
11441    fn validate_etiquetas_rejects_embedded_newline_entry() {
11442        // Canonical paste-from-multiline-doc footgun — the author
11443        // pasted a multi-tag block into one `:etiquetas` entry
11444        // instead of splitting into one entry per tag. Without the
11445        // shape gate `"mesh\nhttp"` silently passed validate and
11446        // landed as a YAML-illegal multi-line scalar in the rendered
11447        // Chart.yaml `keywords:` array.
11448        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
11449        let err = c.validate_etiquetas().unwrap_err();
11450        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11451            panic!("expected EtiquetaInvalid, got {err:?}");
11452        };
11453        assert_eq!(etiqueta, "mesh\nhttp");
11454        assert!(reason.contains("newline"), "got: {reason}");
11455    }
11456
11457    #[test]
11458    fn validate_etiquetas_rejects_embedded_comma_entry() {
11459        // Canonical CSV-list-separator-confusion footgun: the author
11460        // confused the CSV-style separator convention with the
11461        // `:etiquetas` list grammar. Without the shape gate
11462        // `"mesh,http,grpc"` silently passed validate and landed as a
11463        // single malformed search tag in the rendered Chart.yaml
11464        // `keywords:` array — Artifact Hub's keyword index would
11465        // either silently drop the tag or index it as
11466        // `mesh,http,grpc` instead of three separate tags.
11467        let c = caixa_with_etiquetas(vec!["mesh,http,grpc"]);
11468        let err = c.validate_etiquetas().unwrap_err();
11469        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11470            panic!("expected EtiquetaInvalid, got {err:?}");
11471        };
11472        assert_eq!(etiqueta, "mesh,http,grpc");
11473        assert!(reason.contains('`'), "got: {reason}");
11474        assert!(reason.contains(','), "got: {reason}");
11475    }
11476
11477    #[test]
11478    fn validate_etiquetas_rejects_embedded_slash_entry() {
11479        // Canonical path-separator-confusion footgun: the author
11480        // confused namespace-path notation with the keyword grammar.
11481        let c = caixa_with_etiquetas(vec!["caixa/servico"]);
11482        let err = c.validate_etiquetas().unwrap_err();
11483        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11484            panic!("expected EtiquetaInvalid, got {err:?}");
11485        };
11486        assert_eq!(etiqueta, "caixa/servico");
11487        assert!(reason.contains('/'), "got: {reason}");
11488    }
11489
11490    #[test]
11491    fn validate_etiquetas_rejects_leading_digit_entry() {
11492        // Canonical paste-from-numbered-list footgun: the author
11493        // copied `1. mesh` from a numbered doc and the `1` leaked
11494        // into the tag.
11495        let c = caixa_with_etiquetas(vec!["1mesh"]);
11496        let err = c.validate_etiquetas().unwrap_err();
11497        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11498            panic!("expected EtiquetaInvalid, got {err:?}");
11499        };
11500        assert_eq!(etiqueta, "1mesh");
11501        assert!(reason.contains("digit"), "got: {reason}");
11502    }
11503
11504    #[test]
11505    fn validate_etiquetas_rejects_leading_hyphen_entry() {
11506        // Canonical kebab-leak footgun.
11507        let c = caixa_with_etiquetas(vec!["-foo"]);
11508        let err = c.validate_etiquetas().unwrap_err();
11509        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11510            panic!("expected EtiquetaInvalid, got {err:?}");
11511        };
11512        assert_eq!(etiqueta, "-foo");
11513        assert!(reason.contains('-'), "got: {reason}");
11514    }
11515
11516    #[test]
11517    fn validate_etiquetas_rejects_non_ascii_entry() {
11518        // Canonical paste-from-Unicode-doc footgun. Every legitimate
11519        // search tag is strict ASCII; raw non-ASCII silently
11520        // round-trips inconsistently across NFC/NFD normalization on
11521        // APFS / case-folding filesystems and breaks the Artifact Hub
11522        // keyword search index lookup.
11523        let c = caixa_with_etiquetas(vec!["café"]);
11524        let err = c.validate_etiquetas().unwrap_err();
11525        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11526            panic!("expected EtiquetaInvalid, got {err:?}");
11527        };
11528        assert_eq!(etiqueta, "café");
11529        assert!(reason.contains("non-ASCII"), "got: {reason}");
11530    }
11531
11532    #[test]
11533    fn validate_etiquetas_rejects_period_entry() {
11534        // Canonical namespace-confusion / version-suffix footgun
11535        // (`"http.1"` / `"v1.0"`): Cargo's crates.io keyword grammar
11536        // excludes `.` from the continuation set even though the
11537        // sibling `:caracteristicas` axis (Cargo's feature-name
11538        // grammar) admits it. Tighter than the sibling axis, peer
11539        // with Cargo's own crates.io keyword shape.
11540        let c = caixa_with_etiquetas(vec!["http.1"]);
11541        let err = c.validate_etiquetas().unwrap_err();
11542        let ManifestError::EtiquetaInvalid { etiqueta, reason } = err else {
11543            panic!("expected EtiquetaInvalid, got {err:?}");
11544        };
11545        assert_eq!(etiqueta, "http.1");
11546        assert!(reason.contains('.'), "got: {reason}");
11547    }
11548
11549    #[test]
11550    fn validate_etiquetas_empty_takes_precedence_over_shape() {
11551        // Per-entry empty-first cascade pin: an entry that is both
11552        // empty *and* shape-invalid surfaces `EtiquetaEmpty` (the
11553        // narrower "this entry has no value" structural defect
11554        // dominates the broader shape-predicate diagnostic). The
11555        // empty arm fires before the shape predicate is consulted,
11556        // mirroring the peer `validate_autores_empty_takes_precedence_over_shape`
11557        // cascade established on the sibling universal-axis Vec<String>
11558        // surface.
11559        let c = caixa_with_etiquetas(vec![""]);
11560        let err = c.validate_etiquetas().unwrap_err();
11561        assert!(matches!(err, ManifestError::EtiquetaEmpty), "got {err:?}",);
11562    }
11563
11564    #[test]
11565    fn validate_etiquetas_shape_takes_precedence_over_duplicate() {
11566        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
11567        // entry that is malformed surfaces `EtiquetaInvalid` even when
11568        // a later entry would have collided on duplicate. The
11569        // per-entry shape arm fires inside the same loop iteration as
11570        // the empty arm, before the seen-set insert at end-of-iteration
11571        // — structural per-entry defects dominate the cross-entry
11572        // uniqueness diagnostic. Mirrors the peer
11573        // `validate_autores_shape_takes_precedence_over_duplicate`.
11574        let c = caixa_with_etiquetas(vec!["mesh\nhttp", "mesh\nhttp"]);
11575        let err = c.validate_etiquetas().unwrap_err();
11576        assert!(
11577            matches!(err, ManifestError::EtiquetaInvalid { .. }),
11578            "got {err:?}",
11579        );
11580    }
11581
11582    #[test]
11583    fn validate_etiquetas_invalid_diagnostic_names_offending_slot_and_value() {
11584        // Diagnostic-shape pin on the new shape arm (peer with
11585        // `validate_autores_invalid_diagnostic_names_offending_slot_and_value`):
11586        // the rendered Display surfaces both the offending slot name
11587        // and the offending value verbatim, so a `feira lint` run
11588        // points the author at the exact `:etiquetas` entry to fix.
11589        let c = caixa_with_etiquetas(vec!["mesh\nhttp"]);
11590        let rendered = c.validate_etiquetas().unwrap_err().to_string();
11591        assert!(
11592            rendered.contains(":etiquetas"),
11593            "diagnostic must name the offending slot: {rendered}",
11594        );
11595        assert!(
11596            rendered.contains("mesh\\nhttp"),
11597            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11598        );
11599    }
11600
11601    #[test]
11602    fn validate_etiquetas_rejects_at_21_byte_boundary() {
11603        // The 20-byte cap pin — boundary-exceeding case rejected,
11604        // boundary-accepting case passes. Mirrors the peer
11605        // `chart_keyword_shape_rejects_at_21_byte_boundary` substrate-
11606        // side pin, surfaced at the per-axis caller so the cap
11607        // propagates through validate end-to-end. Constructed as a
11608        // single all-`a` token so only the cap arm fires.
11609        let max_ok = "a".repeat(20);
11610        let c = caixa_with_etiquetas(vec![max_ok.as_str()]);
11611        c.validate_etiquetas().unwrap();
11612        let too_long = "a".repeat(21);
11613        let c = caixa_with_etiquetas(vec![too_long.as_str()]);
11614        let err = c.validate_etiquetas().unwrap_err();
11615        let ManifestError::EtiquetaInvalid { reason, .. } = err else {
11616            panic!("expected EtiquetaInvalid, got {err:?}");
11617        };
11618        assert!(reason.contains("20"), "got: {reason}");
11619        assert!(reason.contains("21"), "got: {reason}");
11620    }
11621
11622    #[test]
11623    fn validate_etiquetas_accepts_canonical_shaped_forms() {
11624        // Positive control sweep: every canonical-shaped tag from the
11625        // hello-rio / checkout-aplicacao / pangea-tatara-akeyless
11626        // example fixtures plus the substrate-fixed tags caixa-helm
11627        // unions in at chart render. Drift between this list and the
11628        // substrate-side `chart_keyword_shape_accepts_canonical_forms`
11629        // sweep surfaces here — one source of truth for the rule.
11630        let c = caixa_with_etiquetas(vec![
11631            "example",
11632            "aplicacao",
11633            "mesh",
11634            "ecommerce",
11635            "demo",
11636            "infrastructure",
11637            "aws",
11638            "akeyless",
11639            "pangea-native",
11640            "hello-world",
11641            "wasm",
11642            "rust",
11643            "tatara-lisp",
11644            "caixa-servico",
11645            "lareira",
11646        ]);
11647        c.validate_etiquetas().unwrap();
11648    }
11649
11650    // ── validate_autores — universal-axis maintainer shape ────────────
11651
11652    fn caixa_with_autores(autores: Vec<&str>) -> Caixa {
11653        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11654        c.autores = autores.into_iter().map(String::from).collect();
11655        c
11656    }
11657
11658    #[test]
11659    fn validate_autores_accepts_empty_list() {
11660        // The empty-list identity: `Caixa::template` emits `:autores ()`,
11661        // so the gate is non-disruptive against every existing manifest.
11662        let c = caixa_with_autores(vec![]);
11663        c.validate_autores().unwrap();
11664    }
11665
11666    #[test]
11667    fn validate_autores_accepts_canonical_forms() {
11668        // Positive control sweep: every canonical-shaped non-empty
11669        // distinct maintainer list passes — the hello-rio / checkout-
11670        // aplicacao fixtures' `:autores ("pleme-io")` shape, plus the
11671        // multi-author shape downstream packaging surfaces emit.
11672        let c = caixa_with_autores(vec!["pleme-io"]);
11673        c.validate_autores().unwrap();
11674        let c = caixa_with_autores(vec!["alice <alice@example.com>", "bob <bob@example.com>"]);
11675        c.validate_autores().unwrap();
11676    }
11677
11678    #[test]
11679    fn validate_autores_rejects_empty_entry() {
11680        // Canonical paste-from-blank-doc footgun. Without the gate the
11681        // empty entry rendered as `maintainers: [{name: "", email: null}]`
11682        // in `Chart.yaml`, a no-op maintainer the substrate cannot route
11683        // to.
11684        let c = caixa_with_autores(vec![""]);
11685        let err = c.validate_autores().unwrap_err();
11686        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11687    }
11688
11689    #[test]
11690    fn validate_autores_rejects_duplicate_entry() {
11691        // Canonical copy-paste-the-wrong-author footgun. Unlike the
11692        // `:etiquetas` peer (caixa-helm's `BTreeSet` collect silently
11693        // dedups the rendered `keywords:` array), the `maintainers:`
11694        // rendering has *no* dedup — duplicates stack verbatim. The
11695        // duplicate-arm names the offending author verbatim.
11696        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
11697        let err = c.validate_autores().unwrap_err();
11698        let ManifestError::AutorDuplicate { autor } = err else {
11699            panic!("expected AutorDuplicate, got {err:?}");
11700        };
11701        assert_eq!(autor, "pleme-io");
11702    }
11703
11704    #[test]
11705    fn validate_autores_empty_takes_precedence_over_duplicate() {
11706        // Empty-first cascade pin: `("" "pleme-io" "pleme-io")` surfaces
11707        // `AutorEmpty` not `AutorDuplicate` — the narrower structural
11708        // "this entry has no value" defect dominates the cross-entry
11709        // uniqueness diagnostic. Mirrors the peer empty-before-duplicate
11710        // cascades on `:etiquetas` (`EtiquetaEmpty` before
11711        // `EtiquetaDuplicate`, 360a499), `:caracteristicas`
11712        // (`CaracteristicaEmpty` before `CaracteristicaDuplicate`,
11713        // fc3b4d5), and `:membros :caixa` (`MembroCaixaEmpty` before
11714        // `MembroDuplicate`).
11715        let c = caixa_with_autores(vec!["", "pleme-io", "pleme-io"]);
11716        let err = c.validate_autores().unwrap_err();
11717        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11718    }
11719
11720    #[test]
11721    fn validate_autores_duplicate_reports_first_collision() {
11722        // First-collision pin: `("a" "b" "a" "b")` surfaces the `"a"`
11723        // duplicate (the lexicographically-earliest offending position
11724        // — the second `"a"` at index 2 collides with the first `"a"`
11725        // at index 0), not the later `"b"` collision at index 3,
11726        // peer with every other first-collision diagnostic posture on
11727        // this surface.
11728        let c = caixa_with_autores(vec!["a", "b", "a", "b"]);
11729        let err = c.validate_autores().unwrap_err();
11730        let ManifestError::AutorDuplicate { autor } = err else {
11731            panic!("expected AutorDuplicate, got {err:?}");
11732        };
11733        assert_eq!(autor, "a");
11734    }
11735
11736    #[test]
11737    fn validate_autores_case_sensitive() {
11738        // Case-sensitivity pin: `("Pleme-io" "pleme-io")` is two distinct
11739        // entries, mirroring the peer `:etiquetas` / `:membros :caixa`
11740        // / `:children :caixa` exact-string-match discipline.
11741        let c = caixa_with_autores(vec!["Pleme-io", "pleme-io"]);
11742        c.validate_autores().unwrap();
11743    }
11744
11745    #[test]
11746    fn validate_autores_diagnostic_carries_offending_author() {
11747        // Diagnostic-shape pin (peer with
11748        // `validate_etiquetas_diagnostic_carries_offending_tag`): the
11749        // error's Display surfaces the offending author verbatim, so a
11750        // `feira lint` run can render the diagnostic without re-parsing
11751        // and the author can grep their caixa.lisp for the offending
11752        // value.
11753        let c = caixa_with_autores(vec!["pleme-io", "pleme-io"]);
11754        let rendered = c.validate_autores().unwrap_err().to_string();
11755        assert!(
11756            rendered.contains(":autores"),
11757            "diagnostic must name the offending slot: {rendered}",
11758        );
11759        assert!(
11760            rendered.contains("pleme-io"),
11761            "diagnostic must quote the offending author: {rendered}",
11762        );
11763    }
11764
11765    #[test]
11766    fn validate_autores_rejects_leading_whitespace_entry() {
11767        // Canonical paste-from-aligned-doc footgun. Without the shape
11768        // gate `" pleme-io"` silently passed validate and landed as a
11769        // YAML plain-style scalar with leading whitespace in the
11770        // rendered Chart.yaml `maintainers:` array — every YAML 1.2
11771        // dumper trims leading whitespace from plain-style scalars, so
11772        // the authored space round-tripped inconsistently back through
11773        // `caixa.lisp`. Mirrors the peer
11774        // `validate_descricao_rejects_leading_whitespace`.
11775        let c = caixa_with_autores(vec![" pleme-io"]);
11776        let err = c.validate_autores().unwrap_err();
11777        let ManifestError::AutorInvalid { autor, reason } = err else {
11778            panic!("expected AutorInvalid, got {err:?}");
11779        };
11780        assert_eq!(autor, " pleme-io");
11781        assert!(reason.contains("whitespace"), "got: {reason}");
11782    }
11783
11784    #[test]
11785    fn validate_autores_rejects_trailing_whitespace_entry() {
11786        // Canonical paste-from-doc footgun.
11787        let c = caixa_with_autores(vec!["pleme-io "]);
11788        let err = c.validate_autores().unwrap_err();
11789        let ManifestError::AutorInvalid { autor, reason } = err else {
11790            panic!("expected AutorInvalid, got {err:?}");
11791        };
11792        assert_eq!(autor, "pleme-io ");
11793        assert!(reason.contains("whitespace"), "got: {reason}");
11794    }
11795
11796    #[test]
11797    fn validate_autores_rejects_embedded_newline_entry() {
11798        // Canonical paste-from-multiline-doc footgun — the author
11799        // pasted a multi-line block of author records into one
11800        // `:autores` entry instead of splitting into one entry per
11801        // author. Without the shape gate `"alice\nbob"` silently
11802        // passed validate and landed as a YAML-illegal multi-line
11803        // scalar in the rendered Chart.yaml `maintainers:` array.
11804        let c = caixa_with_autores(vec!["alice\nbob"]);
11805        let err = c.validate_autores().unwrap_err();
11806        let ManifestError::AutorInvalid { autor, reason } = err else {
11807            panic!("expected AutorInvalid, got {err:?}");
11808        };
11809        assert_eq!(autor, "alice\nbob");
11810        assert!(reason.contains("newline"), "got: {reason}");
11811    }
11812
11813    #[test]
11814    fn validate_autores_rejects_embedded_carriage_return_entry() {
11815        // Canonical paste-from-Windows-CRLF-doc footgun.
11816        let c = caixa_with_autores(vec!["alice\rbob"]);
11817        let err = c.validate_autores().unwrap_err();
11818        let ManifestError::AutorInvalid { autor, reason } = err else {
11819            panic!("expected AutorInvalid, got {err:?}");
11820        };
11821        assert_eq!(autor, "alice\rbob");
11822        assert!(reason.contains("carriage return"), "got: {reason}");
11823    }
11824
11825    #[test]
11826    fn validate_autores_rejects_embedded_tab_entry() {
11827        // Canonical tab-from-aligned-doc footgun.
11828        let c = caixa_with_autores(vec!["Pleme\tContributors"]);
11829        let err = c.validate_autores().unwrap_err();
11830        let ManifestError::AutorInvalid { autor, reason } = err else {
11831            panic!("expected AutorInvalid, got {err:?}");
11832        };
11833        assert_eq!(autor, "Pleme\tContributors");
11834        assert!(reason.contains("tab"), "got: {reason}");
11835    }
11836
11837    #[test]
11838    fn validate_autores_rejects_embedded_control_bytes_entry() {
11839        // Paste-from-binary-blob footguns: NUL, BEL, ESC, DEL all
11840        // surface the same control-byte arm.
11841        for entry in [
11842            "alice\x00bob",
11843            "alice\x07bob",
11844            "alice\x1bbob",
11845            "alice\x7fbob",
11846        ] {
11847            let c = caixa_with_autores(vec![entry]);
11848            let err = c.validate_autores().unwrap_err();
11849            let ManifestError::AutorInvalid { autor, reason } = err else {
11850                panic!("expected AutorInvalid for {entry:?}, got {err:?}");
11851            };
11852            assert_eq!(autor, entry);
11853            assert!(
11854                reason.contains("control character"),
11855                "{entry:?} reason: {reason}",
11856            );
11857        }
11858    }
11859
11860    #[test]
11861    fn validate_autores_accepts_unicode_entry() {
11862        // Unicode positive control: realistic maintainer names carry
11863        // Unicode (`François`, `日本語`, `naïve`). The predicate must
11864        // round-trip Unicode losslessly, peer with the
11865        // `chart_maintainer_name_shape_accepts_unicode` substrate-side
11866        // sweep.
11867        let c = caixa_with_autores(vec![
11868            "François Dupont",
11869            "日本語の名前",
11870            "naïve <naive@example.com>",
11871        ]);
11872        c.validate_autores().unwrap();
11873    }
11874
11875    #[test]
11876    fn validate_autores_empty_takes_precedence_over_shape() {
11877        // Per-entry empty-first cascade pin: an entry that is both
11878        // empty *and* shape-invalid surfaces `AutorEmpty` (the narrower
11879        // "this entry has no value" structural defect dominates the
11880        // broader shape-predicate diagnostic). The empty arm fires
11881        // before the shape predicate is consulted, mirroring the peer
11882        // `validate_repositorio_empty_takes_precedence_over_shape`
11883        // cascade on the universal `Option<String>` siblings — and now
11884        // established on the Vec<String> per-entry surface.
11885        let c = caixa_with_autores(vec![""]);
11886        let err = c.validate_autores().unwrap_err();
11887        assert!(matches!(err, ManifestError::AutorEmpty), "got {err:?}",);
11888    }
11889
11890    #[test]
11891    fn validate_autores_shape_takes_precedence_over_duplicate() {
11892        // Per-entry shape-before-cross-entry-duplicate cascade pin: an
11893        // entry that is malformed surfaces `AutorInvalid` even when a
11894        // later entry would have collided on duplicate. The per-entry
11895        // shape arm fires inside the same loop iteration as the empty
11896        // arm, before the seen-set insert at end-of-iteration —
11897        // structural per-entry defects dominate the cross-entry
11898        // uniqueness diagnostic.
11899        let c = caixa_with_autores(vec!["alice\nbob", "alice\nbob"]);
11900        let err = c.validate_autores().unwrap_err();
11901        assert!(
11902            matches!(err, ManifestError::AutorInvalid { .. }),
11903            "got {err:?}",
11904        );
11905    }
11906
11907    #[test]
11908    fn validate_autores_invalid_diagnostic_names_offending_slot_and_value() {
11909        // Diagnostic-shape pin on the new shape arm (peer with
11910        // `validate_descricao_invalid_diagnostic_carries_offending_value`):
11911        // the rendered Display surfaces both the offending slot name
11912        // and the offending value verbatim, so a `feira lint` run
11913        // points the author at the exact `:autores` entry to fix.
11914        let c = caixa_with_autores(vec!["alice\nbob"]);
11915        let rendered = c.validate_autores().unwrap_err().to_string();
11916        assert!(
11917            rendered.contains(":autores"),
11918            "diagnostic must name the offending slot: {rendered}",
11919        );
11920        assert!(
11921            rendered.contains("alice\\nbob"),
11922            "diagnostic must quote the offending value (debug-escaped): {rendered}",
11923        );
11924    }
11925
11926    #[test]
11927    fn validate_autores_rejects_at_129_byte_boundary() {
11928        // The 128-byte cap pin — boundary-exceeding case rejected,
11929        // boundary-accepting case passes. Mirrors the peer
11930        // `chart_maintainer_name_shape_rejects_at_129_byte_boundary`
11931        // substrate-side pin, surfaced at the per-axis caller so the
11932        // cap propagates through validate end-to-end. Constructed as
11933        // a single all-`a` token so only the cap arm fires.
11934        let max_ok = "a".repeat(128);
11935        let c = caixa_with_autores(vec![max_ok.as_str()]);
11936        c.validate_autores().unwrap();
11937        let too_long = "a".repeat(129);
11938        let c = caixa_with_autores(vec![too_long.as_str()]);
11939        let err = c.validate_autores().unwrap_err();
11940        let ManifestError::AutorInvalid { reason, .. } = err else {
11941            panic!("expected AutorInvalid, got {err:?}");
11942        };
11943        assert!(reason.contains("128"), "got: {reason}");
11944        assert!(reason.contains("129"), "got: {reason}");
11945    }
11946
11947    // ── validate_repositorio — universal-axis git-repo-URL shape ──────
11948
11949    fn caixa_with_repositorio(repositorio: Option<&str>) -> Caixa {
11950        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
11951        c.repositorio = repositorio.map(String::from);
11952        c
11953    }
11954
11955    #[test]
11956    fn validate_repositorio_accepts_none() {
11957        // The omit-the-slot identity: `:repositorio` is optional. The
11958        // gate is a no-op when the author didn't declare a value —
11959        // every caixa without a `:repositorio` line trivially passes,
11960        // and the substrate-side renderers fall back to their
11961        // documented placeholder (`caixa-helm`'s `home: None`,
11962        // `caixa-flux`'s `https://github.com/pleme-io/<nome>` derived
11963        // URL). Mirrors the peer `validate_restart_window_accepts_none`
11964        // posture on the other `Option<String>` Caixa slot.
11965        let c = caixa_with_repositorio(None);
11966        c.validate_repositorio().unwrap();
11967    }
11968
11969    #[test]
11970    fn validate_repositorio_accepts_canonical_forms() {
11971        // Positive control sweep across every documented `:repositorio`
11972        // authoring shape — the same union the shared
11973        // `crate::render::is_git_repo_url` predicate accepts and the
11974        // peer `:deps :fonte :repo` axis already routes through.
11975        // Covers the `github:` shorthand (the canonical pleme-io
11976        // convention used in the `:repositorio` field of every
11977        // manifest fixture across `caixa-helm` / `caixa-mesh` and the
11978        // `examples/`), the `https://…` URL the README quickstart uses,
11979        // the `ssh://`, `git://`, `git@host:path` scp-style SSH, and
11980        // `file://` URL schemes the shared predicate documents.
11981        for repo in [
11982            "github:pleme-io/hello-rio",
11983            "github:pleme-io/checkout",
11984            "https://github.com/pleme-io/hello-rio",
11985            "ssh://git@github.com/pleme-io/hello-rio.git",
11986            "git://github.com/pleme-io/hello-rio.git",
11987            "git@github.com:pleme-io/hello-rio.git",
11988            "file:///srv/pleme/hello-rio",
11989        ] {
11990            let c = caixa_with_repositorio(Some(repo));
11991            c.validate_repositorio()
11992                .unwrap_or_else(|err| panic!("canonical {repo:?} must pass: {err:?}"));
11993        }
11994    }
11995
11996    #[test]
11997    fn validate_repositorio_rejects_empty_some() {
11998        // Canonical paste-from-blank-doc footgun. The narrower
11999        // [`ManifestError::RepositorioEmpty`] arm fires before the
12000        // shape predicate is consulted, mirroring the empty-first
12001        // cascade every peer per-axis identity gate uses
12002        // (`NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
12003        // `FonteRepoEmpty` → `FonteRepoInvalid`). Without this gate
12004        // the empty `Some("")` silently passed the renderer's
12005        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
12006        // on `None`) and landed as `home: ""` in `Chart.yaml` /
12007        // `url: ""` in the FluxCD `GitRepository`.
12008        let c = caixa_with_repositorio(Some(""));
12009        let err = c.validate_repositorio().unwrap_err();
12010        assert!(
12011            matches!(err, ManifestError::RepositorioEmpty),
12012            "got {err:?}",
12013        );
12014    }
12015
12016    #[test]
12017    fn validate_repositorio_rejects_whitespace() {
12018        // Paste-from-doc whitespace footgun. The shared
12019        // `is_git_repo_url` predicate refuses any whitespace byte; a
12020        // trailing space in a `:repositorio` value silently broke
12021        // `git clone '<value> '` at clone time. The diagnostic names
12022        // the offending value verbatim.
12023        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio "));
12024        let err = c.validate_repositorio().unwrap_err();
12025        let ManifestError::RepositorioInvalid { repositorio, .. } = err else {
12026            panic!("expected RepositorioInvalid, got {err:?}");
12027        };
12028        assert_eq!(repositorio, "github:pleme-io/hello-rio ");
12029    }
12030
12031    #[test]
12032    fn validate_repositorio_rejects_control_char() {
12033        // Paste-from-multiline-doc CRLF footgun — control characters
12034        // at the URL boundary are a class of subprocess-arg injection
12035        // and break git's URL parser at every porcelain entry point.
12036        let c = caixa_with_repositorio(Some("https://example.com/repo\n"));
12037        let err = c.validate_repositorio().unwrap_err();
12038        assert!(
12039            matches!(err, ManifestError::RepositorioInvalid { .. }),
12040            "got {err:?}",
12041        );
12042    }
12043
12044    #[test]
12045    fn validate_repositorio_rejects_leading_dash() {
12046        // Canonical CLI-argument-injection footgun: `git clone <repo>`
12047        // interprets a leading `-` as a CLI flag, so a
12048        // `-upload-pack=…` value escapes the subprocess argument
12049        // boundary. The shared predicate refuses every leading-`-`
12050        // shape at validate time.
12051        let c = caixa_with_repositorio(Some("-upload-pack=evil"));
12052        let err = c.validate_repositorio().unwrap_err();
12053        assert!(
12054            matches!(err, ManifestError::RepositorioInvalid { .. }),
12055            "got {err:?}",
12056        );
12057    }
12058
12059    #[test]
12060    fn validate_repositorio_rejects_missing_colon_separator() {
12061        // The bare `org/repo` ambiguity footgun — `git clone` reads
12062        // a no-`:` form as a relative filesystem path rather than the
12063        // GitHub-shorthand expansion the author probably intended.
12064        // The shared predicate refuses every shape without a `:`
12065        // separator.
12066        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
12067        let err = c.validate_repositorio().unwrap_err();
12068        assert!(
12069            matches!(err, ManifestError::RepositorioInvalid { .. }),
12070            "got {err:?}",
12071        );
12072    }
12073
12074    #[test]
12075    fn validate_repositorio_rejects_fragment_anchor() {
12076        // Paste-from-browser-address-bar footgun on the
12077        // `:repositorio` axis — an author copies a GitHub permalink
12078        // to a README section / line-permalink and forgets to trim
12079        // the `#fragment` tail. The shared `is_git_repo_url`
12080        // predicate refuses the byte at the URL-grammar layer
12081        // (libcurl strips the fragment before opening the
12082        // transport, so the byte rides verbatim into the rendered
12083        // `Chart.yaml` `home:` and FluxCD `GitRepository` `url:`
12084        // fields but is silently dropped on the wire — two
12085        // manifest variants whose values differ only in their
12086        // fragment anchor lock to two distinct rendered artifacts
12087        // for the byte-identical clone, defeating the THEORY.md
12088        // §V.2 render-determinism contract on the `:repositorio`
12089        // axis the peer `:fonte :repo` axis already closes).
12090        let c = caixa_with_repositorio(Some("https://github.com/pleme-io/hello-rio#readme"));
12091        let err = c.validate_repositorio().unwrap_err();
12092        let ManifestError::RepositorioInvalid {
12093            repositorio,
12094            reason,
12095        } = err
12096        else {
12097            panic!("expected RepositorioInvalid, got {err:?}");
12098        };
12099        assert_eq!(repositorio, "https://github.com/pleme-io/hello-rio#readme");
12100        assert!(
12101            reason.contains("must not contain `#`"),
12102            "reason must surface the fragment-`#` arm, got {reason:?}"
12103        );
12104    }
12105
12106    #[test]
12107    fn validate_repositorio_rejects_query_string() {
12108        // Paste-from-browser-address-bar footgun on the
12109        // `:repositorio` axis (peer with the a68f818 fragment-`#`
12110        // arm on the same axis). An author copies a GitHub tab
12111        // deep-link out of the address bar and forgets to trim
12112        // the `?tab=…` query tail. The shared `is_git_repo_url`
12113        // predicate refuses the byte at the URL-grammar layer
12114        // (GitHub / GitLab / Bitbucket silently ignore the
12115        // `?query` tail and serve the same repo regardless, so
12116        // the byte rides verbatim into the rendered `Chart.yaml`
12117        // `home:` and FluxCD `GitRepository` `url:` fields but
12118        // is silently masked at the wire — two manifest variants
12119        // whose values differ only in their query tail lock to
12120        // two distinct rendered artifacts for the byte-identical
12121        // clone, defeating the THEORY.md §V.2 render-determinism
12122        // contract on the `:repositorio` axis the peer `:fonte
12123        // :repo` axis already closes).
12124        let c = caixa_with_repositorio(Some(
12125            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file",
12126        ));
12127        let err = c.validate_repositorio().unwrap_err();
12128        let ManifestError::RepositorioInvalid {
12129            repositorio,
12130            reason,
12131        } = err
12132        else {
12133            panic!("expected RepositorioInvalid, got {err:?}");
12134        };
12135        assert_eq!(
12136            repositorio,
12137            "https://github.com/pleme-io/hello-rio?tab=readme-ov-file"
12138        );
12139        assert!(
12140            reason.contains("must not contain `?`"),
12141            "reason must surface the query-`?` arm, got {reason:?}"
12142        );
12143    }
12144
12145    #[test]
12146    fn validate_repositorio_rejects_embedded_backslash() {
12147        // Windows-file-path-confusion footgun on the `:repositorio`
12148        // axis (peer with the prior fragment-`#` / query-`?` arms on
12149        // the same axis, and peer with the new dep-level `:fonte :repo`
12150        // backslash arm on the URL-grammar trajectory). An author
12151        // pastes a Windows Explorer address-bar `file:///C:\Users\me\
12152        // hello-rio` into the `:repositorio` slot, expecting the
12153        // `lareira-<nome>` chart's `home:` field and the FluxCD
12154        // `GitRepository` `url:` field to render the canonical local
12155        // file-URI. The shared `is_git_repo_url` predicate refuses
12156        // the byte at the URL-grammar layer (libcurl silently
12157        // translates `\` → `/` on some platforms and refuses it on
12158        // others, so the byte rides verbatim into the rendered
12159        // artifacts but is silently rewritten or rejected at the wire
12160        // — two manifest variants whose values differ only in
12161        // backslash-vs-forward-slash lock to two distinct rendered
12162        // artifacts for the byte-identical clone, defeating the
12163        // THEORY.md §V.2 render-determinism contract on the
12164        // `:repositorio` axis the peer `:fonte :repo` axis already
12165        // closes).
12166        let c = caixa_with_repositorio(Some("file:///C:\\Users\\me\\hello-rio"));
12167        let err = c.validate_repositorio().unwrap_err();
12168        let ManifestError::RepositorioInvalid {
12169            repositorio,
12170            reason,
12171        } = err
12172        else {
12173            panic!("expected RepositorioInvalid, got {err:?}");
12174        };
12175        assert_eq!(repositorio, "file:///C:\\Users\\me\\hello-rio");
12176        assert!(
12177            reason.contains("must not contain `\\`"),
12178            "reason must surface the backslash-`\\` arm, got {reason:?}"
12179        );
12180    }
12181
12182    #[test]
12183    fn validate_repositorio_rejects_uri_template_placeholder() {
12184        // URI Template (RFC 6570) placeholder footgun on the
12185        // `:repositorio` axis (peer with the prior fragment-`#` /
12186        // query-`?` / backslash-`\` arms on the same axis, and peer
12187        // with the new dep-level `:fonte :repo` `{` / `}` arm on the
12188        // URL-grammar trajectory). An author pastes a quick-start
12189        // README snippet / OpenAPI `servers:` URL / Helm chart
12190        // `home:` template carrying unresolved `{org}` / `{repo}`
12191        // placeholders into the `:repositorio` slot, expecting the
12192        // substrate to resolve the placeholder downstream. The
12193        // shared `is_git_repo_url` predicate refuses the byte at the
12194        // URL-grammar layer (libcurl percent-encodes `{` / `}` to
12195        // `%7B` / `%7D` on the wire, so the byte round-trips
12196        // inconsistently between the rendered `Chart.yaml home:` /
12197        // FluxCD `GitRepository url:` and the resolver's `git clone`
12198        // invocation, defeating the THEORY.md §V.2 render-
12199        // determinism contract on the `:repositorio` axis the peer
12200        // `:fonte :repo` axis already closes; every git porcelain
12201        // entry-point additionally fetches a nonexistent literal-
12202        // `{placeholder}`-named path far from the source caixa.lisp).
12203        let c = caixa_with_repositorio(Some("https://github.com/{org}/hello-rio"));
12204        let err = c.validate_repositorio().unwrap_err();
12205        let ManifestError::RepositorioInvalid {
12206            repositorio,
12207            reason,
12208        } = err
12209        else {
12210            panic!("expected RepositorioInvalid, got {err:?}");
12211        };
12212        assert_eq!(repositorio, "https://github.com/{org}/hello-rio");
12213        assert!(
12214            reason.contains("must not contain `{`"),
12215            "reason must surface the open-brace `{{` arm, got {reason:?}"
12216        );
12217        assert!(
12218            reason.contains("URI Template") || reason.contains("RFC 6570"),
12219            "reason must name the RFC 6570 URI Template grammar, got {reason:?}"
12220        );
12221    }
12222
12223    #[test]
12224    fn validate_repositorio_empty_takes_precedence_over_shape() {
12225        // Empty-first cascade pin: the empty `Some("")` surfaces the
12226        // narrower `RepositorioEmpty` not the shape-predicate-wrapped
12227        // `RepositorioInvalid`, mirroring the peer
12228        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid`,
12229        // `FonteRepoEmpty` → `FonteRepoInvalid` cascades. The shared
12230        // `is_git_repo_url` predicate also rejects the empty input
12231        // (defensively, with its own `"must not be empty"` reason),
12232        // but the manifest-layer empty arm runs first to surface the
12233        // narrower diagnostic verbatim.
12234        let c = caixa_with_repositorio(Some(""));
12235        let err = c.validate_repositorio().unwrap_err();
12236        assert!(
12237            matches!(err, ManifestError::RepositorioEmpty),
12238            "got {err:?}",
12239        );
12240    }
12241
12242    #[test]
12243    fn validate_repositorio_diagnostic_carries_offending_value() {
12244        // Diagnostic-shape pin (peer with
12245        // `validate_autores_diagnostic_carries_offending_author`): the
12246        // error's Display surfaces the offending value + slot name
12247        // verbatim, so a `feira lint` run can render the diagnostic
12248        // without re-parsing and the author can grep their caixa.lisp
12249        // for the offending `:repositorio` value.
12250        let c = caixa_with_repositorio(Some("pleme-io/hello-rio"));
12251        let rendered = c.validate_repositorio().unwrap_err().to_string();
12252        assert!(
12253            rendered.contains(":repositorio"),
12254            "diagnostic must name the offending slot: {rendered}",
12255        );
12256        assert!(
12257            rendered.contains("pleme-io/hello-rio"),
12258            "diagnostic must quote the offending value: {rendered}",
12259        );
12260    }
12261
12262    // ── validate_descricao — universal-axis Chart.yaml description shape ──
12263
12264    fn caixa_with_descricao(descricao: Option<&str>) -> Caixa {
12265        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12266        c.descricao = descricao.map(String::from);
12267        c
12268    }
12269
12270    #[test]
12271    fn validate_descricao_accepts_none() {
12272        // The omit-the-slot identity: `:descricao` is optional. The
12273        // gate is a no-op when the author didn't declare a value —
12274        // every caixa without a `:descricao` line trivially passes,
12275        // and the substrate-side renderers fall back to their
12276        // documented `caixa.nome`-derived placeholder. Mirrors the
12277        // peer `validate_repositorio_accepts_none` posture on the
12278        // sibling `Option<String>` Caixa slot.
12279        let c = caixa_with_descricao(None);
12280        c.validate_descricao().unwrap();
12281    }
12282
12283    #[test]
12284    fn validate_descricao_accepts_canonical_summary() {
12285        // Positive control: the canonical pleme-io descricao shape —
12286        // a short free-form prose summary — passes the gate. Covers
12287        // the fixture shapes the `caixa-helm` / `caixa-flux` /
12288        // `caixa-mesh` test fixtures use (`"Canonical Rust→wasm32-
12289        // wasip2 caixa Servico."`, `"Checkout flow."`).
12290        for desc in [
12291            "Canonical Rust→wasm32-wasip2 caixa Servico.",
12292            "Checkout flow.",
12293            "AWS provider caixa for tatara-lisp",
12294            "FIXME — describe this caixa",
12295            "x",
12296        ] {
12297            let c = caixa_with_descricao(Some(desc));
12298            c.validate_descricao()
12299                .unwrap_or_else(|err| panic!("canonical {desc:?} must pass: {err:?}"));
12300        }
12301    }
12302
12303    #[test]
12304    fn validate_descricao_rejects_empty_some() {
12305        // Canonical paste-from-blank-doc footgun. Without this gate
12306        // the empty `Some("")` silently passed the renderer's
12307        // `Option::unwrap_or_else(|| <fallback>)` (which only fires
12308        // on `None`) and landed as `description: ""` in `Chart.yaml`
12309        // and a blank `README.md` header. Mirrors the peer
12310        // [`ManifestError::RepositorioEmpty`] empty-arm on the
12311        // sibling `Option<String>` Caixa slot.
12312        let c = caixa_with_descricao(Some(""));
12313        let err = c.validate_descricao().unwrap_err();
12314        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
12315    }
12316
12317    #[test]
12318    fn validate_descricao_rejects_leading_whitespace() {
12319        // Paste-from-aligned-doc footgun: a leading ASCII space the
12320        // bare empty-arm gate accepted, the shape predicate now
12321        // refuses. The diagnostic carries the offending value
12322        // verbatim (with the leading space preserved) so the author
12323        // can grep their caixa.lisp for the exact `:descricao` line
12324        // and fix the round-trip-inconsistent leading whitespace.
12325        // Mirrors the peer
12326        // `validate_licenca_rejects_leading_whitespace` arm on the
12327        // sibling `:licenca` axis.
12328        let c = caixa_with_descricao(Some(" Checkout flow."));
12329        let err = c.validate_descricao().unwrap_err();
12330        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
12331            panic!("expected DescricaoInvalid, got {err:?}");
12332        };
12333        assert_eq!(descricao, " Checkout flow.");
12334        assert!(reason.contains("whitespace"), "got: {reason:?}");
12335    }
12336
12337    #[test]
12338    fn validate_descricao_rejects_trailing_whitespace() {
12339        // Paste-from-doc footgun: a trailing ASCII space the bare
12340        // empty-arm gate accepted, the shape predicate now refuses.
12341        let c = caixa_with_descricao(Some("Checkout flow. "));
12342        let err = c.validate_descricao().unwrap_err();
12343        let ManifestError::DescricaoInvalid { descricao, reason } = err else {
12344            panic!("expected DescricaoInvalid, got {err:?}");
12345        };
12346        assert_eq!(descricao, "Checkout flow. ");
12347        assert!(reason.contains("whitespace"), "got: {reason:?}");
12348    }
12349
12350    #[test]
12351    fn validate_descricao_rejects_embedded_newline() {
12352        // Paste-from-multiline-doc footgun: an embedded LF the bare
12353        // empty-arm gate accepted, the shape predicate now refuses.
12354        // Without this gate the embedded newline silently landed in
12355        // the rendered Chart.yaml as a multi-line YAML block scalar,
12356        // and every chart-aware UI (`helm list`, `helm search`,
12357        // Artifact Hub) renders the description in a single-line
12358        // column so the embedded newline is silently dropped at
12359        // every downstream consumer.
12360        let c = caixa_with_descricao(Some("Checkout\nflow."));
12361        let err = c.validate_descricao().unwrap_err();
12362        assert!(
12363            matches!(err, ManifestError::DescricaoInvalid { .. }),
12364            "got {err:?}",
12365        );
12366        assert!(err.to_string().contains("newline"), "got {err}");
12367    }
12368
12369    #[test]
12370    fn validate_descricao_rejects_embedded_carriage_return() {
12371        // Paste-from-Windows-CRLF-doc footgun.
12372        let c = caixa_with_descricao(Some("Checkout\rflow."));
12373        let err = c.validate_descricao().unwrap_err();
12374        assert!(
12375            matches!(err, ManifestError::DescricaoInvalid { .. }),
12376            "got {err:?}",
12377        );
12378        assert!(err.to_string().contains("carriage return"), "got {err}");
12379    }
12380
12381    #[test]
12382    fn validate_descricao_rejects_embedded_tab() {
12383        // Tab-from-aligned-doc footgun.
12384        let c = caixa_with_descricao(Some("Checkout\tflow."));
12385        let err = c.validate_descricao().unwrap_err();
12386        assert!(
12387            matches!(err, ManifestError::DescricaoInvalid { .. }),
12388            "got {err:?}",
12389        );
12390        assert!(err.to_string().contains("tab"), "got {err}");
12391    }
12392
12393    #[test]
12394    fn validate_descricao_rejects_embedded_control_bytes() {
12395        // Paste-from-binary-blob footgun: every other control byte
12396        // (NUL, BEL, ESC, DEL) is refused at validate time. Mirrors
12397        // the peer SPDX-expression control-byte arm.
12398        for s in [
12399            "Checkout\x00flow.",
12400            "Checkout\x07flow.",
12401            "Checkout\x1bflow.",
12402            "Checkout\x7fflow.",
12403        ] {
12404            let c = caixa_with_descricao(Some(s));
12405            let err = c.validate_descricao().unwrap_err();
12406            assert!(
12407                matches!(err, ManifestError::DescricaoInvalid { .. }),
12408                "{s:?} got {err:?}",
12409            );
12410            assert!(
12411                err.to_string().contains("control character"),
12412                "{s:?} got {err}",
12413            );
12414        }
12415    }
12416
12417    #[test]
12418    fn validate_descricao_accepts_unicode_prose() {
12419        // Positive control: Unicode prose is accepted — the
12420        // canonical fixtures carry `→` (U+2192) and `—` (U+2014),
12421        // and `Caixa::template`'s `"FIXME — describe this caixa"`
12422        // scaffold every `feira init` emits must continue to pass.
12423        for s in [
12424            "Canonical Rust→wasm32-wasip2 caixa Servico.",
12425            "FIXME — describe this caixa",
12426            "Caixa pour le projet tâche",
12427            "日本語の説明",
12428        ] {
12429            let c = caixa_with_descricao(Some(s));
12430            c.validate_descricao()
12431                .unwrap_or_else(|err| panic!("Unicode {s:?} must pass: {err:?}"));
12432        }
12433    }
12434
12435    #[test]
12436    fn validate_descricao_empty_takes_precedence_over_shape() {
12437        // Cascade pin: a `Some("")` surfaces the narrower
12438        // `DescricaoEmpty` arm, not the broader `DescricaoInvalid`
12439        // shape-predicate arm. Mirrors the peer
12440        // `validate_licenca_empty_takes_precedence_over_shape` pin
12441        // on the sibling `:licenca` axis.
12442        let c = caixa_with_descricao(Some(""));
12443        let err = c.validate_descricao().unwrap_err();
12444        assert!(matches!(err, ManifestError::DescricaoEmpty), "got {err:?}",);
12445    }
12446
12447    #[test]
12448    fn validate_descricao_invalid_diagnostic_carries_offending_value_and_slot() {
12449        // Diagnostic-shape pin: the error's Display surfaces both
12450        // the `:descricao` slot name and the offending value
12451        // verbatim, so a `feira lint` run can render the diagnostic
12452        // without re-parsing and the author can grep their caixa.lisp
12453        // for the offending `:descricao` line. Mirrors the peer
12454        // `validate_licenca_invalid_diagnostic_carries_offending_value_and_slot`
12455        // pin (ee2e888) on the sibling `:licenca` axis.
12456        // The `{descricao:?}` Debug format escapes embedded control
12457        // bytes; the quoted offending value surfaces as
12458        // `"Checkout\nflow."` (literal backslash-n) in the rendered
12459        // diagnostic. The author can grep their caixa.lisp for the
12460        // literal `Checkout` summary prefix.
12461        let c = caixa_with_descricao(Some("Checkout\nflow."));
12462        let rendered = c.validate_descricao().unwrap_err().to_string();
12463        assert!(
12464            rendered.contains(":descricao"),
12465            "diagnostic must name the offending slot: {rendered}",
12466        );
12467        assert!(
12468            rendered.contains("Checkout\\nflow."),
12469            "diagnostic must quote the offending value (debug-escaped): {rendered}",
12470        );
12471    }
12472
12473    #[test]
12474    fn validate_descricao_template_passes() {
12475        // Round-trip pin: the bare `Caixa::template` shape carries
12476        // `:descricao "FIXME — describe this caixa"` (a non-empty
12477        // sentinel), so the template-derived Caixa passes the gate by
12478        // construction. A future template-shape change that omits or
12479        // empties `:descricao` would surface here as a regression.
12480        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12481        c.validate_descricao().unwrap();
12482    }
12483
12484    #[test]
12485    fn validate_descricao_diagnostic_names_offending_slot() {
12486        // Diagnostic-shape pin (peer with
12487        // `validate_repositorio_diagnostic_carries_offending_value`):
12488        // the error's Display surfaces the `:descricao` slot name
12489        // verbatim, so a `feira lint` run can render the diagnostic
12490        // without re-parsing and the author can grep their caixa.lisp
12491        // for the offending `:descricao` line.
12492        let c = caixa_with_descricao(Some(""));
12493        let rendered = c.validate_descricao().unwrap_err().to_string();
12494        assert!(
12495            rendered.contains(":descricao"),
12496            "diagnostic must name the offending slot: {rendered}",
12497        );
12498    }
12499
12500    // ── validate_licenca — universal-axis chart README license shape ──
12501
12502    fn caixa_with_licenca(licenca: Option<&str>) -> Caixa {
12503        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12504        c.licenca = licenca.map(String::from);
12505        c
12506    }
12507
12508    #[test]
12509    fn validate_licenca_accepts_none() {
12510        // The omit-the-slot identity: `:licenca` is optional. The
12511        // gate is a no-op when the author didn't declare a value —
12512        // every caixa without a `:licenca` line trivially passes,
12513        // and the substrate-side `caixa-helm` renderer falls back to
12514        // the documented `"MIT"` placeholder. Mirrors the peer
12515        // `validate_descricao_accepts_none` posture on the sibling
12516        // `Option<String>` Caixa slot.
12517        let c = caixa_with_licenca(None);
12518        c.validate_licenca().unwrap();
12519    }
12520
12521    #[test]
12522    fn validate_licenca_accepts_canonical_expressions() {
12523        // Positive control: every canonical SPDX expression shape
12524        // pleme-io carries in its existing fixtures + the canonical
12525        // SPDX dual-license / with-exception / `+`-suffix / grouped /
12526        // user-defined-reference shapes all pass the gate. Covers
12527        // the single-license, `OR`-compound, `AND`-compound,
12528        // `WITH`-exception, parenthesis-grouped, `+`-suffix, and
12529        // `LicenseRef-` / `DocumentRef-:LicenseRef-` shapes — every
12530        // production the SPDX 2.1 expression grammar admits that
12531        // sits within the alphabet floor the
12532        // `is_spdx_expression_shape` predicate enforces.
12533        for lic in [
12534            "MIT",
12535            "Apache-2.0",
12536            "Apache-2.0 OR MIT",
12537            "Apache-2.0 AND MIT",
12538            "BSD-3-Clause",
12539            "MPL-2.0",
12540            "GPL-3.0-or-later",
12541            "GPL-2.0+",
12542            "Apache-2.0 WITH LLVM-exception",
12543            "(MIT OR Apache-2.0) AND BSD-3-Clause",
12544            "(MIT OR Apache-2.0) AND BSD-3-Clause AND ISC",
12545            "LicenseRef-MyLicense",
12546            "DocumentRef-spdx-tool:LicenseRef-MIT-Style",
12547            "x",
12548        ] {
12549            let c = caixa_with_licenca(Some(lic));
12550            c.validate_licenca()
12551                .unwrap_or_else(|err| panic!("canonical {lic:?} must pass: {err:?}"));
12552        }
12553    }
12554
12555    #[test]
12556    fn validate_licenca_rejects_trailing_whitespace() {
12557        // Paste-from-doc whitespace footgun. A trailing space in the
12558        // `:licenca` value would silently break a downstream SPDX
12559        // parser that splits on exact `AND` / `OR` / `WITH` keyword
12560        // boundaries. The shape predicate refuses every trailing
12561        // whitespace byte by construction. Peer with
12562        // `validate_repositorio_rejects_whitespace` and
12563        // `validate_edicao_rejects_trailing_whitespace`.
12564        let c = caixa_with_licenca(Some("MIT "));
12565        let err = c.validate_licenca().unwrap_err();
12566        let ManifestError::LicencaInvalid { licenca, .. } = err else {
12567            panic!("expected LicencaInvalid, got {err:?}");
12568        };
12569        assert_eq!(licenca, "MIT ");
12570    }
12571
12572    #[test]
12573    fn validate_licenca_rejects_leading_whitespace() {
12574        // Symmetric paste-from-doc whitespace footgun on the leading
12575        // boundary — the gate refuses every shape that starts with a
12576        // space byte by construction. Peer with
12577        // `validate_edicao_rejects_leading_whitespace`.
12578        let c = caixa_with_licenca(Some(" MIT"));
12579        let err = c.validate_licenca().unwrap_err();
12580        assert!(
12581            matches!(err, ManifestError::LicencaInvalid { .. }),
12582            "got {err:?}",
12583        );
12584    }
12585
12586    #[test]
12587    fn validate_licenca_rejects_control_char() {
12588        // Paste-from-multiline-doc CRLF footgun — control characters
12589        // at the value boundary land as a malformed line in the
12590        // rendered chart `README.md` `## License` section. Peer with
12591        // `validate_repositorio_rejects_control_char` and
12592        // `validate_edicao_rejects_control_char`.
12593        for lic in ["MIT\n", "MIT\r\n", "MIT\rApache-2.0"] {
12594            let c = caixa_with_licenca(Some(lic));
12595            let err = c.validate_licenca().unwrap_err();
12596            assert!(
12597                matches!(err, ManifestError::LicencaInvalid { .. }),
12598                "expected LicencaInvalid on {lic:?}, got {err:?}",
12599            );
12600        }
12601    }
12602
12603    #[test]
12604    fn validate_licenca_rejects_tab() {
12605        // Tab-from-aligned-doc footgun — SPDX expressions use a
12606        // single ASCII space between tokens; a tab breaks every
12607        // downstream SPDX parser that splits on exact `" "`
12608        // boundaries.
12609        let c = caixa_with_licenca(Some("MIT\tOR Apache-2.0"));
12610        let err = c.validate_licenca().unwrap_err();
12611        assert!(
12612            matches!(err, ManifestError::LicencaInvalid { .. }),
12613            "got {err:?}",
12614        );
12615    }
12616
12617    #[test]
12618    fn validate_licenca_rejects_non_ascii() {
12619        // Smart-quote / non-ASCII paste footgun — SPDX identifiers
12620        // are ASCII per the `idstring = 1*(ALPHA / DIGIT / "-" /
12621        // ".")` production. The shape predicate refuses every
12622        // non-ASCII byte by construction; peer with
12623        // `validate_edicao_rejects_non_ascii_lookalike`.
12624        for lic in ["MIT\u{a0}OR Apache-2.0", "MIT\u{2013}1.0", "Café-1.0"] {
12625            let c = caixa_with_licenca(Some(lic));
12626            let err = c.validate_licenca().unwrap_err();
12627            assert!(
12628                matches!(err, ManifestError::LicencaInvalid { .. }),
12629                "expected LicencaInvalid on {lic:?}, got {err:?}",
12630            );
12631        }
12632    }
12633
12634    #[test]
12635    fn validate_licenca_rejects_underscore() {
12636        // Underscore-instead-of-hyphen typo footgun — `Apache_2.0` /
12637        // `MIT_Style` / `BSD_3_Clause` are familiar shapes from
12638        // snake-case identifier conventions that don't apply to the
12639        // SPDX `idstring` grammar (which admits only `ALPHA / DIGIT /
12640        // "-" / "."`). The shape predicate refuses every underscore
12641        // byte by construction.
12642        for lic in ["Apache_2.0", "MIT_Style", "BSD_3_Clause"] {
12643            let c = caixa_with_licenca(Some(lic));
12644            let err = c.validate_licenca().unwrap_err();
12645            assert!(
12646                matches!(err, ManifestError::LicencaInvalid { .. }),
12647                "expected LicencaInvalid on {lic:?}, got {err:?}",
12648            );
12649        }
12650    }
12651
12652    #[test]
12653    fn validate_licenca_rejects_comma_separator() {
12654        // Comma-instead-of-`OR`-keyword colloquial idiom footgun —
12655        // SPDX expressions compose multiple licenses via `AND` / `OR`
12656        // keywords, not the comma separator. The shape predicate
12657        // refuses every comma byte by construction.
12658        for lic in ["MIT, Apache-2.0", "MIT,Apache-2.0"] {
12659            let c = caixa_with_licenca(Some(lic));
12660            let err = c.validate_licenca().unwrap_err();
12661            assert!(
12662                matches!(err, ManifestError::LicencaInvalid { .. }),
12663                "expected LicencaInvalid on {lic:?}, got {err:?}",
12664            );
12665        }
12666    }
12667
12668    #[test]
12669    fn validate_licenca_rejects_slash_dual_license() {
12670        // Slash-dual-license colloquial idiom footgun — the
12671        // `MIT/Apache-2.0` shape is common in Cargo's pre-SPDX
12672        // `package.license` field but non-SPDX; the SPDX equivalent
12673        // is `MIT OR Apache-2.0`. The shape predicate refuses every
12674        // forward-slash byte by construction.
12675        for lic in ["MIT/Apache-2.0", "MIT/BSD-3-Clause"] {
12676            let c = caixa_with_licenca(Some(lic));
12677            let err = c.validate_licenca().unwrap_err();
12678            assert!(
12679                matches!(err, ManifestError::LicencaInvalid { .. }),
12680                "expected LicencaInvalid on {lic:?}, got {err:?}",
12681            );
12682        }
12683    }
12684
12685    #[test]
12686    fn validate_licenca_rejects_semicolon_separator() {
12687        // Semicolon-list-separator confusion footgun — adjacent to
12688        // the comma-separator idiom, every list-separator-belongs-
12689        // to-list-grammar confusion lands here.
12690        let c = caixa_with_licenca(Some("MIT; Apache-2.0"));
12691        let err = c.validate_licenca().unwrap_err();
12692        assert!(
12693            matches!(err, ManifestError::LicencaInvalid { .. }),
12694            "got {err:?}",
12695        );
12696    }
12697
12698    #[test]
12699    fn validate_licenca_empty_takes_precedence_over_shape() {
12700        // Empty-first cascade pin: the empty `Some("")` surfaces the
12701        // narrower `LicencaEmpty` not the shape-predicate-wrapped
12702        // `LicencaInvalid`, mirroring the peer
12703        // `validate_edicao_empty_takes_precedence_over_shape` and
12704        // `validate_repositorio_empty_takes_precedence_over_shape`
12705        // (`RepositorioEmpty` → `RepositorioInvalid`), `NomeEmpty` →
12706        // `NomeInvalid`, `VersaoEmpty` → `VersaoInvalid` cascades.
12707        // The shape predicate also refuses the empty input
12708        // (defensively — `"must not be empty"`), but the manifest-
12709        // layer empty arm runs first to surface the narrower
12710        // diagnostic verbatim.
12711        let c = caixa_with_licenca(Some(""));
12712        let err = c.validate_licenca().unwrap_err();
12713        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
12714    }
12715
12716    #[test]
12717    fn validate_licenca_invalid_diagnostic_carries_offending_value() {
12718        // Diagnostic-shape pin on the shape-predicate arm (peer with
12719        // `validate_edicao_invalid_diagnostic_carries_offending_value`
12720        // and `validate_repositorio_diagnostic_carries_offending_value`):
12721        // the error's Display surfaces the offending value + slot
12722        // name verbatim, so a `feira lint` run can render the
12723        // diagnostic without re-parsing and the author can grep
12724        // their caixa.lisp for the offending `:licenca` value.
12725        let c = caixa_with_licenca(Some("Apache_2.0"));
12726        let rendered = c.validate_licenca().unwrap_err().to_string();
12727        assert!(
12728            rendered.contains(":licenca"),
12729            "diagnostic must name the offending slot: {rendered}",
12730        );
12731        assert!(
12732            rendered.contains("Apache_2.0"),
12733            "diagnostic must quote the offending value: {rendered}",
12734        );
12735    }
12736
12737    #[test]
12738    fn validate_licenca_rejects_empty_some() {
12739        // Canonical paste-from-blank-doc footgun. Without this gate
12740        // the empty `Some("")` silently passed the renderer's
12741        // `Option::unwrap_or_else(|| "MIT".into())` (which only
12742        // fires on `None`) and landed as a bare trailing period in
12743        // the rendered chart `README.md` `## License` section.
12744        // Mirrors the peer [`ManifestError::DescricaoEmpty`] empty-
12745        // arm on the sibling `Option<String>` Caixa slot.
12746        let c = caixa_with_licenca(Some(""));
12747        let err = c.validate_licenca().unwrap_err();
12748        assert!(matches!(err, ManifestError::LicencaEmpty), "got {err:?}",);
12749    }
12750
12751    #[test]
12752    fn validate_licenca_template_passes() {
12753        // Round-trip pin: the bare `Caixa::template` shape (whether
12754        // it carries `:licenca` or omits it) passes the gate by
12755        // construction. A future template-shape change that
12756        // introduced `(:licenca "")` would surface here as a
12757        // regression. Mirrors the peer
12758        // `validate_descricao_template_passes` pin.
12759        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
12760        c.validate_licenca().unwrap();
12761    }
12762
12763    #[test]
12764    fn validate_licenca_diagnostic_names_offending_slot() {
12765        // Diagnostic-shape pin (peer with
12766        // `validate_descricao_diagnostic_names_offending_slot`):
12767        // the error's Display surfaces the `:licenca` slot name
12768        // verbatim, so a `feira lint` run can render the diagnostic
12769        // without re-parsing and the author can grep their caixa.lisp
12770        // for the offending `:licenca` line.
12771        let c = caixa_with_licenca(Some(""));
12772        let rendered = c.validate_licenca().unwrap_err().to_string();
12773        assert!(
12774            rendered.contains(":licenca"),
12775            "diagnostic must name the offending slot: {rendered}",
12776        );
12777    }
12778
12779    // ── Caixa::licenca — outer top-level Option<&str> scalar accessor ──
12780
12781    #[test]
12782    fn licenca_returns_licenca_byte_string_verbatim_across_permutations() {
12783        // The canonical per-`Caixa` `:licenca` SPDX-expression scalar
12784        // pin: [`Caixa::licenca`] must return the `:licenca` typed
12785        // byte-string verbatim as an `Option<&str>`, byte-equal to the
12786        // raw `self.licenca.as_deref()` access across every
12787        // representative value in the accept-set — `None` (the "omit
12788        // the slot to defer to the caixa-helm renderer's `MIT`
12789        // fallback" arm every existing fixture without a `:licenca`
12790        // line carries), `Some("")` (a past-the-guard sentinel that
12791        // pins the accessor doesn't perform a silent
12792        // `Some("") → None` collapse on the empty arm — validate
12793        // rejects `Some("")` through `LicencaEmpty` but the accessor
12794        // must ship the raw slot verbatim so a validate-time gate
12795        // regression surfaces at the caixa-helm emit boundary rather
12796        // than being silently absorbed into the fallback), `Some("MIT")`
12797        // (the canonical single-license shape every `feira init`
12798        // template scaffolds), `Some("Apache-2.0 OR MIT")` (the
12799        // canonical `OR`-compound shape the peer
12800        // `validate_licenca_accepts_canonical_expressions` positive
12801        // sweep exercises), `Some("(MIT OR Apache-2.0) AND
12802        // BSD-3-Clause")` (the canonical parenthesis-grouped shape),
12803        // `Some("MIT ")` / `Some(" MIT")` / `Some("MIT\n")` /
12804        // `Some("Apache_2.0")` / `Some("MIT,Apache-2.0")` (past-the-
12805        // guard sentinels — validate rejects each through
12806        // `LicencaInvalid` but the accessor must ship the raw slot
12807        // verbatim).
12808        //
12809        // First outer top-level [`Caixa`] `Option<&str>`-return scalar
12810        // accessor pin on the substrate primitive — opens the "outer
12811        // [`Caixa`] `Option<&str>` scalar" projection pattern the
12812        // sibling per-`Caixa` `:descricao` / `:repositorio` / `:edicao`
12813        // future lifts fold on. Sibling in shape to the peer per-`:placement`
12814        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12815        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12816        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12817        // axes, extended onto the outer top-level [`Caixa`] universal-
12818        // axis surface. Pins against a future silent detour that
12819        // returned an owned `Option<String>` (which would type-check
12820        // but silently allocate on every accessor call, breaking the
12821        // zero-cost projection every peer sibling accessor carries), a
12822        // `Some("") → None` collapse (which would silently absorb the
12823        // `LicencaEmpty` refusal case at the accessor boundary and the
12824        // caixa-helm emit path would silently fall back to `"MIT"` on
12825        // a struct-literal `Caixa { licenca: Some(""), .. }`), or a
12826        // `None → Some("MIT")` collapse (which would silently reify
12827        // the caixa-helm renderer's `"MIT"` fallback at the accessor
12828        // boundary and every downstream consumer keying off the
12829        // `Option::is_none()` discriminator would lose the "author
12830        // omitted the slot" signal).
12831        for licenca in [
12832            None,
12833            Some(""),
12834            Some("MIT"),
12835            Some("Apache-2.0 OR MIT"),
12836            Some("(MIT OR Apache-2.0) AND BSD-3-Clause"),
12837            Some("MIT "),
12838            Some(" MIT"),
12839            Some("MIT\n"),
12840            Some("Apache_2.0"),
12841            Some("MIT,Apache-2.0"),
12842        ] {
12843            let c = caixa_with_licenca(licenca);
12844            assert_eq!(
12845                c.licenca(),
12846                licenca,
12847                "Caixa::licenca must return :licenca verbatim (got {:?}, \
12848                 expected {licenca:?})",
12849                c.licenca(),
12850            );
12851            assert_eq!(
12852                c.licenca(),
12853                c.licenca.as_deref(),
12854                "Caixa::licenca must byte-equal the raw \
12855                 `self.licenca.as_deref()` field access across every \
12856                 value in the Option<&str> accept-set",
12857            );
12858        }
12859    }
12860
12861    #[test]
12862    fn validate_licenca_empty_arm_routes_through_accessor() {
12863        // Composition pin: [`Caixa::validate_licenca`]'s empty-arm gate
12864        // must key off [`Caixa::licenca`], not the raw
12865        // `self.licenca.as_deref()` field access. Structurally: a
12866        // `Caixa { licenca: Some(""), .. }` must surface the
12867        // `LicencaEmpty` refusal exactly, and a
12868        // `Caixa { licenca: Some("MIT"), .. }` (the canonical
12869        // single-license form) must pass validate. The pair jointly
12870        // pins the accessor + validate-gate composition: any future
12871        // silent detour that had the accessor return `None` on the
12872        // empty arm (a `.filter(|s| !s.is_empty())` collapse) would
12873        // silently absorb the `LicencaEmpty` refusal at the accessor
12874        // boundary and the validate gate would accept a struct-literal
12875        // `Caixa { licenca: Some(""), .. }` — the composition pin
12876        // catches that at caixa-core build time.
12877        //
12878        // Peer of the per-`:politicas :circuit-breaker`
12879        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
12880        // accessor-composition pin
12881        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
12882        // on the sibling per-M3-mesh-slot required-`u32` axis — same
12883        // "the validate / shape-gate predicate must route through the
12884        // substrate-primitive typed dispatch" discipline extended onto
12885        // the outer top-level [`Caixa`] universal-axis
12886        // `Option<&str>`-composition surface.
12887        let c = caixa_with_licenca(Some(""));
12888        assert!(
12889            matches!(c.validate_licenca(), Err(ManifestError::LicencaEmpty)),
12890            "validate_licenca must reject licenca == Some(\"\") with \
12891             LicencaEmpty — the accessor and the validate gate must \
12892             route through the same substrate-primitive typed dispatch \
12893             on the :licenca empty arm",
12894        );
12895        let c = caixa_with_licenca(Some("MIT"));
12896        assert!(
12897            c.validate_licenca().is_ok(),
12898            "validate_licenca must accept licenca == Some(\"MIT\") \
12899             (the canonical single-license SPDX shape)",
12900        );
12901    }
12902
12903    #[test]
12904    fn licenca_projects_option_str_by_borrow() {
12905        // The by-borrow pin: [`Caixa::licenca`] returns
12906        // `Option<&str>` by borrow — the `&str` borrows the underlying
12907        // `String` storage of the `Option<String>` slot and the
12908        // accessor must not allocate a fresh `String` on every call.
12909        // Peer of the per-`:placement`
12910        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
12911        // borrow pin on the peer per-M3-mesh-slot
12912        // `Option<&str>`-return axis, extended onto the outer top-
12913        // level [`Caixa`] universal-axis `Option<&str>` shape — the
12914        // accessor's returned `&str` must borrow from `&self` (the
12915        // returned reference's lifetime is tied to `&self`), and
12916        // calling the accessor twice on the same [`Caixa`] must yield
12917        // the same `Option<&str>` verbatim (idempotent, no side
12918        // effects on `&self`).
12919        //
12920        // Pins against a future silent detour that returned an owned
12921        // `Option<String>` (which would type-check but silently
12922        // allocate on every call, breaking the zero-cost projection
12923        // every peer sibling accessor carries), or a one-arm-only
12924        // accessor that returned a saturating value on some sentinel
12925        // input (breaking the pass-through invariant the sibling
12926        // required-scalar accessors carry).
12927        for licenca in [None, Some(""), Some("MIT"), Some("Apache-2.0 OR MIT")] {
12928            let c = caixa_with_licenca(licenca);
12929            let first = c.licenca();
12930            let second = c.licenca();
12931            assert_eq!(
12932                first, second,
12933                "Caixa::licenca must be idempotent — two successive \
12934                 calls on the same &self must return the same \
12935                 Option<&str>",
12936            );
12937            assert_eq!(
12938                first, licenca,
12939                "Caixa::licenca must return :licenca verbatim by \
12940                 borrow — got {first:?}, expected {licenca:?}",
12941            );
12942        }
12943    }
12944
12945    // ── Caixa::repositorio — outer top-level Option<&str> scalar accessor ──
12946
12947    #[test]
12948    fn repositorio_returns_repositorio_byte_string_verbatim_across_permutations() {
12949        // The canonical per-`Caixa` `:repositorio` git-repo-URL scalar
12950        // pin: [`Caixa::repositorio`] must return the `:repositorio`
12951        // typed byte-string verbatim as an `Option<&str>`, byte-equal
12952        // to the raw `self.repositorio.as_deref()` access across every
12953        // representative value in the accept-set — `None` (the "omit
12954        // the slot to defer to the per-renderer placeholder" arm every
12955        // existing fixture without a `:repositorio` line carries),
12956        // `Some("")` (a past-the-guard sentinel that pins the accessor
12957        // doesn't perform a silent `Some("") → None` collapse on the
12958        // empty arm — validate rejects `Some("")` through
12959        // `RepositorioEmpty` but the accessor must ship the raw slot
12960        // verbatim so a validate-time gate regression surfaces at the
12961        // caixa-helm / caixa-flux emit boundary rather than being
12962        // silently absorbed into the per-renderer fallback),
12963        // `Some("github:pleme-io/hello-rio")` (the canonical `github:`
12964        // shorthand every existing manifest fixture across
12965        // `caixa-helm` / `caixa-mesh` and the `examples/` uses),
12966        // `Some("https://github.com/pleme-io/checkout")` (the canonical
12967        // `https://` URL the README quickstart uses),
12968        // `Some("ssh://git@github.com/pleme-io/checkout.git")` /
12969        // `Some("git://github.com/pleme-io/checkout.git")` /
12970        // `Some("git@github.com:pleme-io/checkout.git")` /
12971        // `Some("file:///opt/mirrors/pleme-io/checkout")` (every non-
12972        // github scheme the shared `is_git_repo_url` predicate
12973        // documents), and five past-the-guard sentinels for the
12974        // `RepositorioInvalid` refusal cases (`Some("pleme-io/checkout")`
12975        // missing-colon, `Some("-upload-pack=evil")` leading-dash, /
12976        // `Some("github:pleme-io/checkout?ref=main")` query-string, /
12977        // `Some("github:pleme-io/checkout#main")` fragment-anchor, /
12978        // `Some("github:pleme-io/{tpl}")` URI-template-placeholder — the
12979        // sentinels pin the accessor doesn't silently absorb the
12980        // refusal cases into a fallback).
12981        //
12982        // Second outer top-level [`Caixa`] `Option<&str>`-return scalar
12983        // accessor pin on the substrate primitive — sibling of the peer
12984        // [`Caixa::licenca`] (6d5bc28) pin
12985        // (`licenca_returns_licenca_byte_string_verbatim_across_permutations`)
12986        // that opened the "outer [`Caixa`] `Option<&str>` scalar"
12987        // projection pin pattern this pin folds on. Sibling in shape to
12988        // the peer per-`:placement`
12989        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
12990        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
12991        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
12992        // axes, extended onto the outer top-level [`Caixa`] universal-
12993        // axis surface. Pins against a future silent detour that
12994        // returned an owned `Option<String>` (which would type-check
12995        // but silently allocate on every accessor call, breaking the
12996        // zero-cost projection every peer sibling accessor carries), a
12997        // `Some("") → None` collapse (which would silently absorb the
12998        // `RepositorioEmpty` refusal case at the accessor boundary and
12999        // the caixa-helm `Chart.yaml` `home:` fold would silently
13000        // render a `home: null` / omitted field on a struct-literal
13001        // `Caixa { repositorio: Some(""), .. }`), or a
13002        // `None → Some(<default>)` collapse (which would silently reify
13003        // the per-renderer fallback at the accessor boundary and every
13004        // downstream consumer keying off the `Option::is_none()`
13005        // discriminator would lose the "author omitted the slot"
13006        // signal).
13007        for repositorio in [
13008            None,
13009            Some(""),
13010            Some("github:pleme-io/hello-rio"),
13011            Some("https://github.com/pleme-io/checkout"),
13012            Some("ssh://git@github.com/pleme-io/checkout.git"),
13013            Some("git://github.com/pleme-io/checkout.git"),
13014            Some("git@github.com:pleme-io/checkout.git"),
13015            Some("file:///opt/mirrors/pleme-io/checkout"),
13016            Some("pleme-io/checkout"),
13017            Some("-upload-pack=evil"),
13018            Some("github:pleme-io/checkout?ref=main"),
13019            Some("github:pleme-io/checkout#main"),
13020            Some("github:pleme-io/{tpl}"),
13021        ] {
13022            let c = caixa_with_repositorio(repositorio);
13023            assert_eq!(
13024                c.repositorio(),
13025                repositorio,
13026                "Caixa::repositorio must return :repositorio verbatim \
13027                 (got {:?}, expected {repositorio:?})",
13028                c.repositorio(),
13029            );
13030            assert_eq!(
13031                c.repositorio(),
13032                c.repositorio.as_deref(),
13033                "Caixa::repositorio must byte-equal the raw \
13034                 `self.repositorio.as_deref()` field access across every \
13035                 value in the Option<&str> accept-set",
13036            );
13037        }
13038    }
13039
13040    #[test]
13041    fn validate_repositorio_empty_arm_routes_through_accessor() {
13042        // Composition pin: [`Caixa::validate_repositorio`]'s empty-arm
13043        // gate must key off [`Caixa::repositorio`], not the raw
13044        // `self.repositorio.as_deref()` field access. Structurally: a
13045        // `Caixa { repositorio: Some(""), .. }` must surface the
13046        // `RepositorioEmpty` refusal exactly, and a
13047        // `Caixa { repositorio: Some("github:pleme-io/hello-rio"), .. }`
13048        // (the canonical `github:` shorthand form) must pass validate.
13049        // The pair jointly pins the accessor + validate-gate
13050        // composition: any future silent detour that had the accessor
13051        // return `None` on the empty arm (a `.filter(|s| !s.is_empty())`
13052        // collapse) would silently absorb the `RepositorioEmpty` refusal
13053        // at the accessor boundary and the validate gate would accept a
13054        // struct-literal `Caixa { repositorio: Some(""), .. }` — the
13055        // composition pin catches that at caixa-core build time.
13056        //
13057        // Peer of the [`Caixa::licenca`] (6d5bc28)
13058        // `validate_licenca_empty_arm_routes_through_accessor`
13059        // composition pin on the sibling outer top-level [`Caixa`]
13060        // `Option<&str>` universal-axis surface — same "the validate /
13061        // shape-gate predicate must route through the substrate-
13062        // primitive typed dispatch" discipline extended onto the second
13063        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
13064        // composition surface.
13065        let c = caixa_with_repositorio(Some(""));
13066        assert!(
13067            matches!(
13068                c.validate_repositorio(),
13069                Err(ManifestError::RepositorioEmpty),
13070            ),
13071            "validate_repositorio must reject repositorio == Some(\"\") \
13072             with RepositorioEmpty — the accessor and the validate gate \
13073             must route through the same substrate-primitive typed \
13074             dispatch on the :repositorio empty arm",
13075        );
13076        let c = caixa_with_repositorio(Some("github:pleme-io/hello-rio"));
13077        assert!(
13078            c.validate_repositorio().is_ok(),
13079            "validate_repositorio must accept repositorio == \
13080             Some(\"github:pleme-io/hello-rio\") (the canonical \
13081             `github:` shorthand git-repo-URL shape)",
13082        );
13083    }
13084
13085    #[test]
13086    fn repositorio_projects_option_str_by_borrow() {
13087        // The by-borrow pin: [`Caixa::repositorio`] returns
13088        // `Option<&str>` by borrow — the `&str` borrows the underlying
13089        // `String` storage of the `Option<String>` slot and the
13090        // accessor must not allocate a fresh `String` on every call.
13091        // Peer of the per-`:placement`
13092        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) and the
13093        // [`Caixa::licenca`] (6d5bc28) by-borrow pins on the peer
13094        // `Option<&str>`-return axes, extended onto the second outer
13095        // top-level [`Caixa`] universal-axis `Option<&str>` shape —
13096        // the accessor's returned `&str` must borrow from `&self` (the
13097        // returned reference's lifetime is tied to `&self`), and
13098        // calling the accessor twice on the same [`Caixa`] must yield
13099        // the same `Option<&str>` verbatim (idempotent, no side effects
13100        // on `&self`).
13101        //
13102        // Pins against a future silent detour that returned an owned
13103        // `Option<String>` (which would type-check but silently
13104        // allocate on every call, breaking the zero-cost projection
13105        // every peer sibling accessor carries), or a one-arm-only
13106        // accessor that returned a saturating value on some sentinel
13107        // input (breaking the pass-through invariant the sibling
13108        // required-scalar accessors carry).
13109        for repositorio in [
13110            None,
13111            Some(""),
13112            Some("github:pleme-io/hello-rio"),
13113            Some("https://github.com/pleme-io/checkout"),
13114        ] {
13115            let c = caixa_with_repositorio(repositorio);
13116            let first = c.repositorio();
13117            let second = c.repositorio();
13118            assert_eq!(
13119                first, second,
13120                "Caixa::repositorio must be idempotent — two successive \
13121                 calls on the same &self must return the same \
13122                 Option<&str>",
13123            );
13124            assert_eq!(
13125                first, repositorio,
13126                "Caixa::repositorio must return :repositorio verbatim by \
13127                 borrow — got {first:?}, expected {repositorio:?}",
13128            );
13129        }
13130    }
13131
13132    // ── Caixa::canonical_git_url — resolved-git-URL composer ──────────
13133
13134    #[test]
13135    fn canonical_git_url_returns_repositorio_verbatim_on_some_arm() {
13136        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] must
13137        // return the author-declared `:repositorio` byte-string verbatim
13138        // on the `Some` arm — no scheme rewrite, no trailing-slash
13139        // canonicalization, no `github:` → `https://github.com/`
13140        // desugaring. The resolved-URL composer is the projection of
13141        // the raw [`Caixa::repositorio`] `Option<&str>` accessor onto
13142        // the `String`-return arity every substrate-side field-fill
13143        // consumer keys off; on the `Some` arm the projection is
13144        // `str::to_owned` verbatim, so every accept-set value the
13145        // sibling `repositorio_returns_repositorio_byte_string_verbatim_
13146        // across_permutations` pin covers (`https://…`, `github:…`,
13147        // `ssh://…`, `git://…`, `git@…`, `file://…`, and the past-the-
13148        // guard sentinel `pleme-io/…`) must survive the accessor
13149        // byte-equal. Pins against a future silent detour that rewrote
13150        // the `github:` shorthand to the `https://github.com/` full URL
13151        // at the accessor boundary (which would silently split the
13152        // resolved-URL surface from the raw [`Caixa::repositorio`]
13153        // accessor's documented pass-through invariant), or a trailing-
13154        // slash normalization (which would silently break the
13155        // FluxCD `GitRepository` `spec.url` byte-exact match every
13156        // downstream consumer keys the source-controller reconcile off).
13157        for repositorio in [
13158            "github:pleme-io/hello-rio",
13159            "https://github.com/pleme-io/checkout",
13160            "ssh://git@github.com/pleme-io/checkout.git",
13161            "git://github.com/pleme-io/checkout.git",
13162            "git@github.com:pleme-io/checkout.git",
13163            "file:///opt/mirrors/pleme-io/checkout",
13164        ] {
13165            let c = caixa_with_repositorio(Some(repositorio));
13166            assert_eq!(
13167                c.canonical_git_url(),
13168                repositorio,
13169                "Caixa::canonical_git_url on the Some arm must return \
13170                 :repositorio verbatim (got {:?}, expected {repositorio:?})",
13171                c.canonical_git_url(),
13172            );
13173        }
13174    }
13175
13176    #[test]
13177    fn canonical_git_url_falls_back_to_pleme_org_url_on_none_arm() {
13178        // Fail-before-pass-after pin: [`Caixa::canonical_git_url`] on the
13179        // `None` arm must emit the substrate's canonical pleme-org github
13180        // URL derived from `caixa.nome()` — `https://github.com/<org>/
13181        // <nome>` with `<org>` bound to [`crate::DEFAULT_PLEME_GIT_ORG`]
13182        // and `<nome>` bound to the typed [`Caixa::nome`] accessor. This
13183        // is the exact byte-image of the prior inline
13184        // [`caixa-flux::ClusterBundleOpts::for_caixa`] `git_url`
13185        // composer at caixa-flux/src/lib.rs:2080 that every prior caller
13186        // re-derived open-coded. Pins against a future silent detour
13187        // that migrated the `<org>` segment to a different constant (a
13188        // fork rebranding that split off a new
13189        // `DEFAULT_PLEME_GIT_ORG_MIRROR` const the accessor would need
13190        // to migrate onto), a scheme change (`https://` → `git://` or
13191        // `ssh://`), or a per-`Caixa` `.canonical_git_url_prefix`
13192        // override (which would break the substrate-wide single-source-
13193        // of-truth guarantee this method encodes).
13194        let c = caixa_with_repositorio(None);
13195        let expected = format!(
13196            "https://github.com/{org}/{nome}",
13197            org = crate::DEFAULT_PLEME_GIT_ORG,
13198            nome = c.nome(),
13199        );
13200        assert_eq!(
13201            c.canonical_git_url(),
13202            expected,
13203            "Caixa::canonical_git_url on the None arm must fold through \
13204             the substrate's canonical pleme-org github URL fallback \
13205             `https://github.com/<DEFAULT_PLEME_GIT_ORG>/<nome>` — got \
13206             {:?}, expected {expected:?}",
13207            c.canonical_git_url(),
13208        );
13209    }
13210
13211    #[test]
13212    fn canonical_git_url_byte_matches_manual_composition() {
13213        // Byte-parity pin: [`Caixa::canonical_git_url`] must render
13214        // byte-identically to the manual open-coded
13215        // `caixa.repositorio().map(str::to_owned).unwrap_or_else(||
13216        //  format!("https://github.com/{org}/{nome}", ...))` composition
13217        // every prior substrate-side caller re-derived. Guards the
13218        // paired-site convergence just applied at caixa-flux's
13219        // [`ClusterBundleOpts::for_caixa`] `git_url` composer (which
13220        // now routes through this accessor): a future implementation of
13221        // this method that reordered the format arguments, swapped the
13222        // `<org>` constant for a different one, or interposed a
13223        // canonicalization pass on the `Some` arm surfaces here as a
13224        // caixa-core build-time test failure rather than as a downstream
13225        // FluxCD `GitRepository` reconcile mismatch far from this
13226        // method's source.
13227        for repositorio in [
13228            None,
13229            Some("github:pleme-io/hello-rio"),
13230            Some("https://github.com/pleme-io/checkout"),
13231            Some("ssh://git@github.com/pleme-io/checkout.git"),
13232        ] {
13233            let c = caixa_with_repositorio(repositorio);
13234            let manual = c.repositorio().map_or_else(
13235                || {
13236                    format!(
13237                        "https://github.com/{org}/{nome}",
13238                        org = crate::DEFAULT_PLEME_GIT_ORG,
13239                        nome = c.nome(),
13240                    )
13241                },
13242                str::to_owned,
13243            );
13244            assert_eq!(
13245                c.canonical_git_url(),
13246                manual,
13247                "Caixa::canonical_git_url must byte-equal the manual \
13248                 open-coded `repositorio().map(str::to_owned)\
13249                 .unwrap_or_else(|| format!(...))` composition across \
13250                 every representative :repositorio input — got {:?}, \
13251                 expected {manual:?}",
13252                c.canonical_git_url(),
13253            );
13254        }
13255    }
13256
13257    // ── Caixa::publish_tag — resolved-publish-tag composer ───────────
13258
13259    #[test]
13260    fn publish_tag_composes_prefix_and_versao_on_all_shapes() {
13261        // Fail-before-pass-after pin: [`Caixa::publish_tag`] must compose
13262        // [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] against the caixa's typed
13263        // [`Caixa::versao`] byte-string across every SemVer-2 shape the
13264        // sibling [`validate_versao_accepts_canonical_forms`] positive-set
13265        // sweep documents — bare MAJOR.MINOR.PATCH, pre-release tags
13266        // (`-rc.1`), build metadata (`+build.42`), the combined form, and
13267        // the `0.0.0` boundary case. Every accept-set value the peer
13268        // validate gate lets through must survive the resolved-tag
13269        // projection byte-equal.
13270        for versao in [
13271            "0.1.0",
13272            "0.0.0",
13273            "1.0.0",
13274            "1.2.3-rc.1",
13275            "1.2.3+build.42",
13276            "1.2.3-rc.1+build.42",
13277        ] {
13278            let c = caixa_with_versao(versao);
13279            let expected = format!(
13280                "{prefix}{versao}",
13281                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13282            );
13283            assert_eq!(
13284                c.publish_tag(),
13285                expected,
13286                "Caixa::publish_tag must compose \
13287                 DEFAULT_PUBLISH_TAG_PREFIX ({prefix:?}) against \
13288                 :versao ({versao:?}) verbatim — got {got:?}, \
13289                 expected {expected:?}",
13290                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13291                got = c.publish_tag(),
13292            );
13293        }
13294    }
13295
13296    #[test]
13297    fn publish_tag_starts_with_default_publish_tag_prefix() {
13298        // Prefix-shape pin: every [`Caixa::publish_tag`] emission must
13299        // begin with the canonical [`crate::DEFAULT_PUBLISH_TAG_PREFIX`]
13300        // byte-string on every input, guarding a hypothetical future
13301        // implementation that migrated the prefix segment to an inline
13302        // literal (`"v"`) that would silently drift from any rebrand of
13303        // the lifted constant. Peer to the sibling caixa-flux
13304        // `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`
13305        // test which pins the same prefix invariant at the reader-side
13306        // `GitRefSpec::Tag` emit site.
13307        for versao in ["0.0.0", "0.1.0", "1.2.3-rc.1", "9.9.9+build.1"] {
13308            let c = caixa_with_versao(versao);
13309            let tag = c.publish_tag();
13310            assert!(
13311                tag.starts_with(crate::DEFAULT_PUBLISH_TAG_PREFIX),
13312                "Caixa::publish_tag emission {tag:?} must start with \
13313                 the lifted crate::DEFAULT_PUBLISH_TAG_PREFIX \
13314                 ({prefix:?})",
13315                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13316            );
13317        }
13318    }
13319
13320    #[test]
13321    fn publish_tag_byte_matches_manual_composition() {
13322        // Byte-parity pin: [`Caixa::publish_tag`] must render byte-
13323        // identically to the manual open-coded
13324        // `format!("{prefix}{versao}", prefix =
13325        //  caixa_core::DEFAULT_PUBLISH_TAG_PREFIX, versao =
13326        //  caixa.versao())` composition every prior substrate-side
13327        // caller re-derived. Guards the paired-site convergence just
13328        // applied at caixa-flux's [`ClusterBundleOpts::for_caixa`]
13329        // `git_ref` composer (which now routes through this accessor):
13330        // a future implementation of this method that reordered the
13331        // format arguments, swapped the `<prefix>` constant for a
13332        // different one, or interposed a canonicalization pass on the
13333        // `:versao` axis surfaces here as a caixa-core build-time test
13334        // failure rather than as a downstream FluxCD `GitRepository`
13335        // reconcile mismatch far from this method's source.
13336        for versao in [
13337            "0.1.0",
13338            "0.0.0",
13339            "1.2.3-rc.1",
13340            "1.2.3+build.42",
13341            "1.2.3-rc.1+build.42",
13342        ] {
13343            let c = caixa_with_versao(versao);
13344            let manual = format!(
13345                "{prefix}{versao}",
13346                prefix = crate::DEFAULT_PUBLISH_TAG_PREFIX,
13347                versao = c.versao(),
13348            );
13349            assert_eq!(
13350                c.publish_tag(),
13351                manual,
13352                "Caixa::publish_tag must byte-equal the manual \
13353                 open-coded `format!(\"{{prefix}}{{versao}}\", ...)` \
13354                 composition across every representative :versao input \
13355                 — got {got:?}, expected {manual:?}",
13356                got = c.publish_tag(),
13357            );
13358        }
13359    }
13360
13361    // ── Caixa::lareira_chart_name — resolved-chart-name composer ─────
13362
13363    #[test]
13364    fn lareira_chart_name_composes_prefix_and_nome_on_all_shapes() {
13365        // Fail-before-pass-after pin: [`Caixa::lareira_chart_name`] must
13366        // compose [`crate::LAREIRA_CHART_NAME_PREFIX`] against the caixa's
13367        // typed [`Caixa::nome`] byte-string across every DNS-1123 shape
13368        // the sibling [`validate_nome_accepts_canonical_forms`] positive-
13369        // set sweep documents — single-word, hyphen-joined, version-
13370        // suffixed, single-char, two-char, digit-start, retry-suffixed.
13371        // Every accept-set value the peer validate gate lets through must
13372        // survive the resolved-chart-name projection byte-equal.
13373        for nome in [
13374            "checkout",
13375            "cart-v2",
13376            "a",
13377            "db",
13378            "3rd-party-shim",
13379            "payment-retry",
13380            "0",
13381        ] {
13382            let c = caixa_with_nome(nome);
13383            let expected = format!("{prefix}{nome}", prefix = crate::LAREIRA_CHART_NAME_PREFIX);
13384            assert_eq!(
13385                c.lareira_chart_name(),
13386                expected,
13387                "Caixa::lareira_chart_name must compose \
13388                 LAREIRA_CHART_NAME_PREFIX ({prefix:?}) against \
13389                 :nome ({nome:?}) verbatim — got {got:?}, \
13390                 expected {expected:?}",
13391                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
13392                got = c.lareira_chart_name(),
13393            );
13394        }
13395    }
13396
13397    #[test]
13398    fn lareira_chart_name_starts_with_lifted_prefix() {
13399        // Prefix-shape pin: every [`Caixa::lareira_chart_name`] emission
13400        // must begin with the canonical
13401        // [`crate::LAREIRA_CHART_NAME_PREFIX`] byte-string on every
13402        // input, guarding a hypothetical future implementation that
13403        // migrated the prefix segment to an inline literal (`"lareira-"`)
13404        // that would silently drift from any rebrand of the lifted
13405        // constant. Peer to the sibling
13406        // [`publish_tag_starts_with_default_publish_tag_prefix`] pin on
13407        // the co-resident resolved-publish-tag composer's prefix axis.
13408        for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
13409            let c = caixa_with_nome(nome);
13410            let chart = c.lareira_chart_name();
13411            assert!(
13412                chart.starts_with(crate::LAREIRA_CHART_NAME_PREFIX),
13413                "Caixa::lareira_chart_name emission {chart:?} must start \
13414                 with the lifted crate::LAREIRA_CHART_NAME_PREFIX \
13415                 ({prefix:?})",
13416                prefix = crate::LAREIRA_CHART_NAME_PREFIX,
13417            );
13418        }
13419    }
13420
13421    #[test]
13422    fn lareira_chart_name_byte_matches_canonical_helper_composition() {
13423        // Byte-parity pin: [`Caixa::lareira_chart_name`] must render
13424        // byte-identically to the manual open-coded
13425        // `caixa_core::lareira_chart_name(caixa.nome())` two-step
13426        // composition every prior substrate-side caller re-derived.
13427        // Guards the paired-site convergence just applied at caixa-helm's
13428        // [`render_chart_for_servico_with`] `ChartDir.name` composer,
13429        // caixa-flux's [`cluster_bundle`] per-CR `chart_name` binding,
13430        // and caixa-tatara's [`process_for_aplicacao`] `release_name`
13431        // composer (all of which now route through this accessor): a
13432        // future implementation of this method that reordered the
13433        // composition arguments, swapped the `<prefix>` constant for a
13434        // different one, or interposed a canonicalization pass on the
13435        // `:nome` axis surfaces here as a caixa-core build-time test
13436        // failure rather than as a downstream Helm chart-render / FluxCD
13437        // reconcile / tatara Process-CR mismatch far from this method's
13438        // source.
13439        for nome in [
13440            "checkout",
13441            "cart-v2",
13442            "a",
13443            "db",
13444            "3rd-party-shim",
13445            "payment-retry",
13446        ] {
13447            let c = caixa_with_nome(nome);
13448            let manual = crate::lareira_chart_name(c.nome());
13449            assert_eq!(
13450                c.lareira_chart_name(),
13451                manual,
13452                "Caixa::lareira_chart_name must byte-equal the manual \
13453                 open-coded `caixa_core::lareira_chart_name(caixa.nome())` \
13454                 composition across every representative :nome input — \
13455                 got {got:?}, expected {manual:?}",
13456                got = c.lareira_chart_name(),
13457            );
13458        }
13459    }
13460
13461    // ── Caixa::oci_chart_ref — resolved-OCI-chart-ref composer ────────
13462
13463    #[test]
13464    fn oci_chart_ref_composes_scheme_and_lareira_chart_name_on_all_shapes() {
13465        // Fail-before-pass-after pin: [`Caixa::oci_chart_ref`] must
13466        // compose [`crate::OCI_SCHEME_PREFIX`] + the caller-supplied
13467        // `registry` + [`crate::lareira_chart_name`]-of-[`Caixa::nome`]
13468        // across the full paired `(registry, :nome)` accept-set — every
13469        // representative registry the substrate-side emitters carry
13470        // (`ghcr.io/pleme-io/charts`, the canonical CAIXA-SDLC §II
13471        // ArtifactHub-tier registry; `ghcr.io/pleme-io`, the bare-org
13472        // arm the sibling `oci_chart_ref_pins_byte_shape_against_prior_
13473        // inline_format` render-side pin exercises; `registry.example.
13474        // com`, an off-org shape; `localhost:5000`, the local-dev shape
13475        // every `feira chart` iteration path lands under) × every DNS-
13476        // 1123 `:nome` shape the peer `validate_nome_accepts_canonical_
13477        // forms` positive-set sweep documents (single-word, hyphen-
13478        // joined, single-char, two-char, digit-start, retry-suffixed).
13479        // Every accept-set pair the peer validate gates let through must
13480        // survive the resolved-OCI-ref projection byte-equal.
13481        for registry in [
13482            "ghcr.io/pleme-io/charts",
13483            "ghcr.io/pleme-io",
13484            "registry.example.com",
13485            "localhost:5000",
13486        ] {
13487            for nome in [
13488                "checkout",
13489                "cart-v2",
13490                "a",
13491                "db",
13492                "3rd-party-shim",
13493                "payment-retry",
13494                "0",
13495            ] {
13496                let c = caixa_with_nome(nome);
13497                let expected = format!(
13498                    "{scheme}{registry}/{chart}",
13499                    scheme = crate::OCI_SCHEME_PREFIX,
13500                    chart = crate::lareira_chart_name(nome),
13501                );
13502                assert_eq!(
13503                    c.oci_chart_ref(registry),
13504                    expected,
13505                    "Caixa::oci_chart_ref must compose \
13506                     OCI_SCHEME_PREFIX ({scheme:?}) + registry ({registry:?}) + \
13507                     lareira_chart_name(:nome ({nome:?})) verbatim — got {got:?}, \
13508                     expected {expected:?}",
13509                    scheme = crate::OCI_SCHEME_PREFIX,
13510                    got = c.oci_chart_ref(registry),
13511                );
13512            }
13513        }
13514    }
13515
13516    #[test]
13517    fn oci_chart_ref_starts_with_lifted_scheme_prefix() {
13518        // Scheme-prefix-shape pin: every [`Caixa::oci_chart_ref`]
13519        // emission must begin with the canonical
13520        // [`crate::OCI_SCHEME_PREFIX`] byte-string on every input, guarding
13521        // a hypothetical future implementation that migrated the scheme
13522        // segment to an inline literal (`"oci://"`) that would silently
13523        // drift from any rebrand of the lifted constant. Peer to the
13524        // sibling [`publish_tag_starts_with_default_publish_tag_prefix`]
13525        // + [`lareira_chart_name_starts_with_lifted_prefix`] pins on the
13526        // co-resident resolved-publish-tag / resolved-chart-name
13527        // composers' prefix axes.
13528        for registry in [
13529            "ghcr.io/pleme-io/charts",
13530            "ghcr.io/pleme-io",
13531            "localhost:5000",
13532        ] {
13533            for nome in ["checkout", "cart", "a", "payment-retry", "0"] {
13534                let c = caixa_with_nome(nome);
13535                let ref_ = c.oci_chart_ref(registry);
13536                assert!(
13537                    ref_.starts_with(crate::OCI_SCHEME_PREFIX),
13538                    "Caixa::oci_chart_ref emission {ref_:?} must start \
13539                     with the lifted crate::OCI_SCHEME_PREFIX ({scheme:?}) \
13540                     — registry ({registry:?}), :nome ({nome:?})",
13541                    scheme = crate::OCI_SCHEME_PREFIX,
13542                );
13543            }
13544        }
13545    }
13546
13547    #[test]
13548    fn oci_chart_ref_byte_matches_canonical_helper_composition() {
13549        // Byte-parity pin: [`Caixa::oci_chart_ref`] must render byte-
13550        // identically to the manual open-coded
13551        // `caixa_core::oci_chart_ref(registry, caixa.nome())` two-step
13552        // composition every prior substrate-side caller re-derived.
13553        // Guards the paired-site convergence just applied at caixa-
13554        // tatara's [`derive_chart_ref`] helper (which now routes through
13555        // this accessor): a future implementation of this method that
13556        // reordered the composition arguments, swapped the `<scheme>`
13557        // constant for a different one, migrated the `<chart>` segment
13558        // off the paired [`crate::lareira_chart_name`] composer, or
13559        // interposed a canonicalization pass on either input axis
13560        // surfaces here as a caixa-core build-time test failure rather
13561        // than as a downstream `helm install` / FluxCD OCI-source
13562        // reconcile / tatara `Process`-CR mismatch far from this
13563        // method's source. Sibling to the peer
13564        // [`lareira_chart_name_byte_matches_canonical_helper_composition`]
13565        // / [`publish_tag_byte_matches_manual_composition`] /
13566        // [`canonical_git_url_byte_matches_manual_composition`] byte-
13567        // parity pins that carry the same discipline on the co-resident
13568        // resolved-chart-name / resolved-publish-tag / resolved-git-URL
13569        // composers.
13570        for registry in [
13571            "ghcr.io/pleme-io/charts",
13572            "ghcr.io/pleme-io",
13573            "registry.example.com",
13574            "localhost:5000",
13575        ] {
13576            for nome in [
13577                "checkout",
13578                "cart-v2",
13579                "a",
13580                "db",
13581                "3rd-party-shim",
13582                "payment-retry",
13583            ] {
13584                let c = caixa_with_nome(nome);
13585                let manual = crate::oci_chart_ref(registry, c.nome());
13586                assert_eq!(
13587                    c.oci_chart_ref(registry),
13588                    manual,
13589                    "Caixa::oci_chart_ref must byte-equal the manual \
13590                     open-coded `caixa_core::oci_chart_ref(registry, \
13591                     caixa.nome())` composition across every representative \
13592                     (registry, :nome) pair — registry ({registry:?}), \
13593                     :nome ({nome:?}), got {got:?}, expected {manual:?}",
13594                    got = c.oci_chart_ref(registry),
13595                );
13596            }
13597        }
13598    }
13599
13600    // ── Caixa::descricao — outer top-level Option<&str> scalar accessor ──
13601
13602    #[test]
13603    fn descricao_returns_descricao_byte_string_verbatim_across_permutations() {
13604        // The canonical per-`Caixa` `:descricao` free-form-prose scalar
13605        // pin: [`Caixa::descricao`] must return the `:descricao` typed
13606        // byte-string verbatim as an `Option<&str>`, byte-equal to the
13607        // raw `self.descricao.as_deref()` access across every
13608        // representative value in the accept-set — `None` (the "omit
13609        // the slot to defer to the per-renderer `caixa.nome`-derived
13610        // fallback" arm every existing fixture without a `:descricao`
13611        // line carries), `Some("")` (a past-the-guard sentinel that
13612        // pins the accessor doesn't perform a silent `Some("") → None`
13613        // collapse on the empty arm — validate rejects `Some("")`
13614        // through `DescricaoEmpty` but the accessor must ship the raw
13615        // slot verbatim so a validate-time gate regression surfaces at
13616        // the caixa-helm / caixa-feira emit boundary rather than being
13617        // silently absorbed into the per-renderer `caixa.nome`-derived
13618        // fallback), `Some("Checkout flow.")` (the canonical one-line
13619        // prose descriptor the peer
13620        // `validate_descricao_accepts_canonical_value` positive sweep
13621        // exercises), `Some("Canonical Rust→wasm32-wasip2 caixa
13622        // Servico.")` (the multi-byte Unicode continuation-byte shape
13623        // the `hello-rio` fixture carries), `Some("→ — · ✓")` (a
13624        // multi-glyph Unicode shape the peer
13625        // `is_chart_description_shape` predicate accepts), and five
13626        // past-the-guard sentinels for the `DescricaoInvalid` refusal
13627        // cases (`Some(" Checkout flow.")` leading-whitespace,
13628        // `Some("Checkout flow. ")` trailing-whitespace,
13629        // `Some("Checkout\nflow.")` embedded-LF,
13630        // `Some("Checkout\tflow.")` embedded-TAB, and
13631        // `Some("Checkout\x00flow.")` embedded-NUL — the sentinels pin
13632        // the accessor doesn't silently absorb the refusal cases into
13633        // a fallback).
13634        //
13635        // Third outer top-level [`Caixa`] `Option<&str>`-return scalar
13636        // accessor pin on the substrate primitive — sibling of the peer
13637        // [`Caixa::licenca`] (6d5bc28) and [`Caixa::repositorio`]
13638        // (cc7332d) pins that opened the "outer [`Caixa`]
13639        // `Option<&str>` scalar" projection pin pattern this pin folds
13640        // on. Sibling in shape to the peer per-`:placement`
13641        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
13642        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
13643        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
13644        // axes, extended onto the outer top-level [`Caixa`] universal-
13645        // axis surface. Pins against a future silent detour that
13646        // returned an owned `Option<String>` (which would type-check
13647        // but silently allocate on every accessor call, breaking the
13648        // zero-cost projection every peer sibling accessor carries), a
13649        // `Some("") → None` collapse (which would silently absorb the
13650        // `DescricaoEmpty` refusal case at the accessor boundary and
13651        // the caixa-helm `Chart.yaml` `description:` fold would
13652        // silently render a `caixa.nome`-derived fallback on a
13653        // struct-literal `Caixa { descricao: Some(""), .. }`), or a
13654        // `None → Some(<default>)` collapse (which would silently
13655        // reify the per-renderer `caixa.nome`-derived fallback at the
13656        // accessor boundary and every downstream consumer keying off
13657        // the `Option::is_none()` discriminator would lose the "author
13658        // omitted the slot" signal).
13659        for descricao in [
13660            None,
13661            Some(""),
13662            Some("Checkout flow."),
13663            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
13664            Some("→ — · ✓"),
13665            Some(" Checkout flow."),
13666            Some("Checkout flow. "),
13667            Some("Checkout\nflow."),
13668            Some("Checkout\tflow."),
13669            Some("Checkout\x00flow."),
13670        ] {
13671            let c = caixa_with_descricao(descricao);
13672            assert_eq!(
13673                c.descricao(),
13674                descricao,
13675                "Caixa::descricao must return :descricao verbatim (got \
13676                 {:?}, expected {descricao:?})",
13677                c.descricao(),
13678            );
13679            assert_eq!(
13680                c.descricao(),
13681                c.descricao.as_deref(),
13682                "Caixa::descricao must byte-equal the raw \
13683                 `self.descricao.as_deref()` field access across every \
13684                 value in the Option<&str> accept-set",
13685            );
13686        }
13687    }
13688
13689    #[test]
13690    fn validate_descricao_empty_arm_routes_through_accessor() {
13691        // Composition pin: [`Caixa::validate_descricao`]'s empty-arm
13692        // gate must key off [`Caixa::descricao`], not the raw
13693        // `self.descricao.as_deref()` field access. Structurally: a
13694        // `Caixa { descricao: Some(""), .. }` must surface the
13695        // `DescricaoEmpty` refusal exactly, and a
13696        // `Caixa { descricao: Some("Checkout flow."), .. }` (the
13697        // canonical one-line-prose form) must pass validate. The pair
13698        // jointly pins the accessor + validate-gate composition: any
13699        // future silent detour that had the accessor return `None` on
13700        // the empty arm (a `.filter(|s| !s.is_empty())` collapse) would
13701        // silently absorb the `DescricaoEmpty` refusal at the accessor
13702        // boundary and the validate gate would accept a struct-literal
13703        // `Caixa { descricao: Some(""), .. }` — the composition pin
13704        // catches that at caixa-core build time.
13705        //
13706        // Peer of the [`Caixa::licenca`] (6d5bc28)
13707        // `validate_licenca_empty_arm_routes_through_accessor` and
13708        // [`Caixa::repositorio`] (cc7332d)
13709        // `validate_repositorio_empty_arm_routes_through_accessor`
13710        // composition pins on the sibling outer top-level [`Caixa`]
13711        // `Option<&str>` universal-axis surface — same "the validate /
13712        // shape-gate predicate must route through the substrate-
13713        // primitive typed dispatch" discipline extended onto the third
13714        // outer top-level [`Caixa`] universal-axis `Option<&str>`-
13715        // composition surface.
13716        let c = caixa_with_descricao(Some(""));
13717        assert!(
13718            matches!(c.validate_descricao(), Err(ManifestError::DescricaoEmpty),),
13719            "validate_descricao must reject descricao == Some(\"\") \
13720             with DescricaoEmpty — the accessor and the validate gate \
13721             must route through the same substrate-primitive typed \
13722             dispatch on the :descricao empty arm",
13723        );
13724        let c = caixa_with_descricao(Some("Checkout flow."));
13725        assert!(
13726            c.validate_descricao().is_ok(),
13727            "validate_descricao must accept descricao == \
13728             Some(\"Checkout flow.\") (the canonical one-line-prose \
13729             chart-description shape)",
13730        );
13731    }
13732
13733    #[test]
13734    fn descricao_projects_option_str_by_borrow() {
13735        // The by-borrow pin: [`Caixa::descricao`] returns
13736        // `Option<&str>` by borrow — the `&str` borrows the underlying
13737        // `String` storage of the `Option<String>` slot and the
13738        // accessor must not allocate a fresh `String` on every call.
13739        // Peer of the [`Caixa::licenca`] (6d5bc28) and
13740        // [`Caixa::repositorio`] (cc7332d) by-borrow pins on the peer
13741        // outer top-level [`Caixa`] `Option<&str>`-return axes, and of
13742        // the per-`:placement`
13743        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
13744        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
13745        // return axis, extended onto the third outer top-level
13746        // [`Caixa`] universal-axis `Option<&str>` shape — the
13747        // accessor's returned `&str` must borrow from `&self` (the
13748        // returned reference's lifetime is tied to `&self`), and
13749        // calling the accessor twice on the same [`Caixa`] must yield
13750        // the same `Option<&str>` verbatim (idempotent, no side
13751        // effects on `&self`).
13752        //
13753        // Pins against a future silent detour that returned an owned
13754        // `Option<String>` (which would type-check but silently
13755        // allocate on every call, breaking the zero-cost projection
13756        // every peer sibling accessor carries), or a one-arm-only
13757        // accessor that returned a saturating value on some sentinel
13758        // input (breaking the pass-through invariant the sibling
13759        // required-scalar accessors carry).
13760        for descricao in [
13761            None,
13762            Some(""),
13763            Some("Checkout flow."),
13764            Some("Canonical Rust→wasm32-wasip2 caixa Servico."),
13765        ] {
13766            let c = caixa_with_descricao(descricao);
13767            let first = c.descricao();
13768            let second = c.descricao();
13769            assert_eq!(
13770                first, second,
13771                "Caixa::descricao must be idempotent — two successive \
13772                 calls on the same &self must return the same \
13773                 Option<&str>",
13774            );
13775            assert_eq!(
13776                first, descricao,
13777                "Caixa::descricao must return :descricao verbatim by \
13778                 borrow — got {first:?}, expected {descricao:?}",
13779            );
13780        }
13781    }
13782
13783    // ── validate_edicao — universal-axis language-edition shape ──
13784
13785    fn caixa_with_edicao(edicao: Option<&str>) -> Caixa {
13786        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13787        c.edicao = edicao.map(String::from);
13788        c
13789    }
13790
13791    #[test]
13792    fn validate_edicao_accepts_none() {
13793        // The omit-the-slot identity: `:edicao` is optional. The
13794        // gate is a no-op when the author didn't declare a value —
13795        // every caixa without an `:edicao` line trivially passes,
13796        // and the substrate-side build pipeline falls back to the
13797        // documented default edition. Mirrors the peer
13798        // `validate_licenca_accepts_none` posture on the sibling
13799        // `Option<String>` Caixa slot.
13800        let c = caixa_with_edicao(None);
13801        c.validate_edicao().unwrap();
13802    }
13803
13804    #[test]
13805    fn validate_edicao_accepts_canonical_value() {
13806        // Positive control: the canonical `"2026"` edition every
13807        // existing renderer-side fixture (`caixa-helm`, `caixa-flux`,
13808        // `caixa-mesh`) carries by construction passes the gate.
13809        // Future-introduced sibling editions (`"2027"`, `"2030"`,
13810        // `"2049"`) that match the same 4-digit ASCII decimal year
13811        // shape must also trivially pass — the structural shape
13812        // predicate accepts every well-formed year regardless of
13813        // whether the substrate yet understands the specific value
13814        // (a future known-edition allowlist tightens that).
13815        for ed in ["2026", "2027", "2030", "2049"] {
13816            let c = caixa_with_edicao(Some(ed));
13817            c.validate_edicao()
13818                .unwrap_or_else(|err| panic!("canonical {ed:?} must pass: {err:?}"));
13819        }
13820    }
13821
13822    #[test]
13823    fn validate_edicao_rejects_empty_some() {
13824        // Canonical paste-from-blank-doc footgun. Without this gate
13825        // the empty `Some("")` silently lands as `(:edicao "")` in
13826        // the rendered caixa.lisp and a future renderer-side
13827        // consumer's `Option::unwrap_or_else` (which only fires on
13828        // `None`) skips its fallback. Mirrors the peer
13829        // [`ManifestError::LicencaEmpty`] empty-arm on the sibling
13830        // `Option<String>` Caixa slot.
13831        let c = caixa_with_edicao(Some(""));
13832        let err = c.validate_edicao().unwrap_err();
13833        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
13834    }
13835
13836    #[test]
13837    fn validate_edicao_rejects_free_form_non_year() {
13838        // Free-form non-year footgun: the bare `"x"` / `"latest"` /
13839        // `"nightly"` shapes carry no operational meaning on the
13840        // substrate's build-time edition selector. Until this gate
13841        // landed the bare empty-arm check let every such value
13842        // through and broke far from the source caixa.lisp. Peer
13843        // with the shape-predicate cascade
13844        // `validate_repositorio_rejects_missing_colon_separator`
13845        // establishes past its own empty arm.
13846        for ed in ["x", "latest", "nightly", "stable"] {
13847            let c = caixa_with_edicao(Some(ed));
13848            let err = c.validate_edicao().unwrap_err();
13849            assert!(
13850                matches!(err, ManifestError::EdicaoInvalid { .. }),
13851                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13852            );
13853        }
13854    }
13855
13856    #[test]
13857    fn validate_edicao_rejects_trailing_whitespace() {
13858        // Paste-from-doc whitespace footgun. A trailing space in
13859        // the `:edicao` value would silently break the substrate's
13860        // build-time edition match-table lookup at the rendered
13861        // artifact's edition-selector consumer. The shape predicate
13862        // refuses every whitespace byte by construction (any byte
13863        // outside `0-9` fails `is_ascii_digit`). Peer with
13864        // `validate_repositorio_rejects_whitespace`.
13865        let c = caixa_with_edicao(Some("2026 "));
13866        let err = c.validate_edicao().unwrap_err();
13867        let ManifestError::EdicaoInvalid { edicao, .. } = err else {
13868            panic!("expected EdicaoInvalid, got {err:?}");
13869        };
13870        assert_eq!(edicao, "2026 ");
13871    }
13872
13873    #[test]
13874    fn validate_edicao_rejects_leading_whitespace() {
13875        // Symmetric paste-from-doc whitespace footgun on the leading
13876        // boundary — the gate refuses every shape with a non-digit
13877        // byte by construction.
13878        let c = caixa_with_edicao(Some(" 2026"));
13879        let err = c.validate_edicao().unwrap_err();
13880        assert!(
13881            matches!(err, ManifestError::EdicaoInvalid { .. }),
13882            "got {err:?}",
13883        );
13884    }
13885
13886    #[test]
13887    fn validate_edicao_rejects_control_char() {
13888        // Paste-from-multiline-doc CRLF footgun — control characters
13889        // at the value boundary break the substrate's build-time
13890        // edition-selector parser. Peer with
13891        // `validate_repositorio_rejects_control_char`.
13892        let c = caixa_with_edicao(Some("2026\n"));
13893        let err = c.validate_edicao().unwrap_err();
13894        assert!(
13895            matches!(err, ManifestError::EdicaoInvalid { .. }),
13896            "got {err:?}",
13897        );
13898    }
13899
13900    #[test]
13901    fn validate_edicao_rejects_non_ascii_lookalike() {
13902        // Fullwidth-keyboard look-alike footgun — `"2026"` is
13903        // the U+FF12 U+FF10 U+FF12 U+FF16 sequence (CJK fullwidth
13904        // digits), 4 codepoints but 12 UTF-8 bytes; the substrate's
13905        // edition selector wants an ASCII year, and the gate
13906        // refuses every non-ASCII shape by construction (length in
13907        // bytes is 12 ≠ 4, *and* every byte falls outside
13908        // `is_ascii_digit`'s `0-9` range).
13909        let c = caixa_with_edicao(Some("2026"));
13910        let err = c.validate_edicao().unwrap_err();
13911        assert!(
13912            matches!(err, ManifestError::EdicaoInvalid { .. }),
13913            "got {err:?}",
13914        );
13915    }
13916
13917    #[test]
13918    fn validate_edicao_rejects_version_tag_prefix() {
13919        // Common version-tag idiom footgun — `"v2026"` / `"e2026"`
13920        // / `"r2026"` are familiar shapes from git-tag / Rust
13921        // edition / release-tag conventions that don't apply to
13922        // the year-shaped edition axis. The shape predicate refuses
13923        // every leading non-digit prefix.
13924        for ed in ["v2026", "e2026", "r2026"] {
13925            let c = caixa_with_edicao(Some(ed));
13926            let err = c.validate_edicao().unwrap_err();
13927            assert!(
13928                matches!(err, ManifestError::EdicaoInvalid { .. }),
13929                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13930            );
13931        }
13932    }
13933
13934    #[test]
13935    fn validate_edicao_rejects_decimal_shape() {
13936        // Decimal-shaped pseudo-version footgun — `"2026.1"` /
13937        // `"2026.0"` are familiar shapes from semver / float
13938        // conventions that don't apply to the year-shaped edition
13939        // axis. The shape predicate refuses every non-digit byte
13940        // (`.` falls outside `is_ascii_digit`).
13941        for ed in ["2026.1", "2026.0", "2026.0.1"] {
13942            let c = caixa_with_edicao(Some(ed));
13943            let err = c.validate_edicao().unwrap_err();
13944            assert!(
13945                matches!(err, ManifestError::EdicaoInvalid { .. }),
13946                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13947            );
13948        }
13949    }
13950
13951    #[test]
13952    fn validate_edicao_rejects_wrong_length_numeric() {
13953        // Wrong-length numeric footgun — `"26"` (truncated) /
13954        // `"202"` (truncated) / `"20260"` (extra digit) / `"00026"`
13955        // (zero-padded too wide) all parse as integers but don't
13956        // name a 4-digit year. The shape predicate refuses every
13957        // value whose length isn't exactly 4 bytes.
13958        for ed in ["26", "202", "20260", "00026", "9"] {
13959            let c = caixa_with_edicao(Some(ed));
13960            let err = c.validate_edicao().unwrap_err();
13961            assert!(
13962                matches!(err, ManifestError::EdicaoInvalid { .. }),
13963                "expected EdicaoInvalid on {ed:?}, got {err:?}",
13964            );
13965        }
13966    }
13967
13968    #[test]
13969    fn validate_edicao_empty_takes_precedence_over_shape() {
13970        // Empty-first cascade pin: the empty `Some("")` surfaces
13971        // the narrower `EdicaoEmpty` not the shape-predicate-
13972        // wrapped `EdicaoInvalid`, mirroring the peer
13973        // `validate_repositorio_empty_takes_precedence_over_shape`
13974        // (`RepositorioEmpty` → `RepositorioInvalid`),
13975        // `NomeEmpty` → `NomeInvalid`, `VersaoEmpty` →
13976        // `VersaoInvalid`, `FonteRepoEmpty` → `FonteRepoInvalid`
13977        // cascades. The shape predicate also refuses the empty
13978        // input (defensively — `s.len() != 4`), but the
13979        // manifest-layer empty arm runs first to surface the
13980        // narrower diagnostic verbatim.
13981        let c = caixa_with_edicao(Some(""));
13982        let err = c.validate_edicao().unwrap_err();
13983        assert!(matches!(err, ManifestError::EdicaoEmpty), "got {err:?}",);
13984    }
13985
13986    #[test]
13987    fn validate_edicao_template_passes() {
13988        // Round-trip pin: the bare `Caixa::template` shape (which
13989        // carries `:edicao "2026"` verbatim) passes the gate by
13990        // construction. A future template-shape change that
13991        // introduced `(:edicao "")` or a non-year value would
13992        // surface here as a regression. Mirrors the peer
13993        // `validate_licenca_template_passes` pin.
13994        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
13995        c.validate_edicao().unwrap();
13996    }
13997
13998    #[test]
13999    fn validate_edicao_diagnostic_names_offending_slot() {
14000        // Diagnostic-shape pin (peer with
14001        // `validate_licenca_diagnostic_names_offending_slot`): the
14002        // error's Display surfaces the `:edicao` slot name verbatim,
14003        // so a `feira lint` run can render the diagnostic without
14004        // re-parsing and the author can grep their caixa.lisp for
14005        // the offending `:edicao` line.
14006        let c = caixa_with_edicao(Some(""));
14007        let rendered = c.validate_edicao().unwrap_err().to_string();
14008        assert!(
14009            rendered.contains(":edicao"),
14010            "diagnostic must name the offending slot: {rendered}",
14011        );
14012    }
14013
14014    #[test]
14015    fn validate_edicao_invalid_diagnostic_carries_offending_value() {
14016        // Diagnostic-shape pin on the shape-predicate arm (peer
14017        // with `validate_repositorio_diagnostic_carries_offending_value`):
14018        // the error's Display surfaces the offending value + slot
14019        // name verbatim, so a `feira lint` run can render the
14020        // diagnostic without re-parsing and the author can grep
14021        // their caixa.lisp for the offending `:edicao` value.
14022        let c = caixa_with_edicao(Some("v2026"));
14023        let rendered = c.validate_edicao().unwrap_err().to_string();
14024        assert!(
14025            rendered.contains(":edicao"),
14026            "diagnostic must name the offending slot: {rendered}",
14027        );
14028        assert!(
14029            rendered.contains("v2026"),
14030            "diagnostic must quote the offending value: {rendered}",
14031        );
14032    }
14033
14034    // ── Caixa::edicao — outer top-level Option<&str> scalar accessor ──
14035
14036    #[test]
14037    fn edicao_returns_edicao_byte_string_verbatim_across_permutations() {
14038        // The canonical per-`Caixa` `:edicao` language-edition scalar
14039        // pin: [`Caixa::edicao`] must return the `:edicao` typed
14040        // byte-string verbatim as an `Option<&str>`, byte-equal to the
14041        // raw `self.edicao.as_deref()` access across every representative
14042        // value in the accept-set — `None` (the "omit the slot to defer
14043        // to the substrate's default edition" arm every existing
14044        // [`caixa-resolver`] fixture without an `:edicao` line carries),
14045        // `Some("")` (a past-the-guard sentinel that pins the accessor
14046        // doesn't perform a silent `Some("") → None` collapse on the
14047        // empty arm — validate rejects `Some("")` through `EdicaoEmpty`
14048        // but the accessor must ship the raw slot verbatim so a
14049        // validate-time gate regression surfaces at any future edition-
14050        // aware consumer's boundary rather than being silently absorbed
14051        // into the substrate's default edition), `Some("2026")` (the
14052        // canonical 4-digit-ASCII-decimal-year shape every `feira init`
14053        // template scaffolds via [`Caixa::template`] and every
14054        // renderer-side fixture at `caixa-helm/src/lib.rs:978` /
14055        // `caixa-flux/src/lib.rs:2319` / `caixa-mesh/src/lib.rs:3208`
14056        // carries by construction), `Some("2018")` / `Some("2021")` /
14057        // `Some("2024")` (canonical 4-digit-ASCII-decimal-year shapes
14058        // peer with Cargo's `[package] edition` grammar every future-
14059        // introduced sibling to `"2026"` will follow), and eight
14060        // past-the-guard sentinels for the `EdicaoInvalid` refusal cases
14061        // (`Some("2026 ")` trailing-whitespace, `Some(" 2026")` leading-
14062        // whitespace, `Some("2026\n")` embedded-LF, `Some("2026")`
14063        // fullwidth-non-ASCII-lookalike, `Some("v2026")` version-tag-
14064        // prefix, `Some("2026.1")` decimal-shape, `Some("26")` wrong-
14065        // length-numeric, `Some("latest")` free-form-non-year — the
14066        // sentinels pin the accessor doesn't silently absorb the
14067        // refusal cases into a substrate-default-edition fallback).
14068        //
14069        // Fourth and final outer top-level [`Caixa`] `Option<&str>`-
14070        // return scalar accessor pin on the substrate primitive —
14071        // sibling of the peer [`Caixa::licenca`] (6d5bc28),
14072        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
14073        // (3f16e2f) pins that opened the "outer [`Caixa`]
14074        // `Option<&str>` scalar" projection pin pattern this pin folds
14075        // on. Sibling in shape to the peer per-`:placement`
14076        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) /
14077        // [`crate::aplicacao::Placement::affinity`] (74ec2d3) accessor
14078        // pins on the sibling per-M3-mesh-slot `Option<&str>`-return
14079        // axes, extended onto the outer top-level [`Caixa`] universal-
14080        // axis surface's last unlifted `Option<String>` slot. Pins
14081        // against a future silent detour that returned an owned
14082        // `Option<String>` (which would type-check but silently
14083        // allocate on every accessor call, breaking the zero-cost
14084        // projection every peer sibling accessor carries), a
14085        // `Some("") → None` collapse (which would silently absorb the
14086        // `EdicaoEmpty` refusal case at the accessor boundary and any
14087        // future edition-aware consumer would silently fall back to
14088        // the substrate's default edition on a struct-literal
14089        // `Caixa { edicao: Some(""), .. }`), or a
14090        // `None → Some("2026")` collapse (which would silently reify
14091        // the substrate's default edition at the accessor boundary
14092        // and every downstream consumer keying off the
14093        // `Option::is_none()` discriminator would lose the "author
14094        // omitted the slot" signal).
14095        for edicao in [
14096            None,
14097            Some(""),
14098            Some("2026"),
14099            Some("2018"),
14100            Some("2021"),
14101            Some("2024"),
14102            Some("2026 "),
14103            Some(" 2026"),
14104            Some("2026\n"),
14105            Some("2026"),
14106            Some("v2026"),
14107            Some("2026.1"),
14108            Some("26"),
14109            Some("latest"),
14110        ] {
14111            let c = caixa_with_edicao(edicao);
14112            assert_eq!(
14113                c.edicao(),
14114                edicao,
14115                "Caixa::edicao must return :edicao verbatim (got {:?}, \
14116                 expected {edicao:?})",
14117                c.edicao(),
14118            );
14119            assert_eq!(
14120                c.edicao(),
14121                c.edicao.as_deref(),
14122                "Caixa::edicao must byte-equal the raw \
14123                 `self.edicao.as_deref()` field access across every \
14124                 value in the Option<&str> accept-set",
14125            );
14126        }
14127    }
14128
14129    #[test]
14130    fn validate_edicao_empty_arm_routes_through_accessor() {
14131        // Composition pin: [`Caixa::validate_edicao`]'s empty-arm gate
14132        // must key off [`Caixa::edicao`], not the raw
14133        // `self.edicao.as_deref()` field access. Structurally: a
14134        // `Caixa { edicao: Some(""), .. }` must surface the
14135        // `EdicaoEmpty` refusal exactly, and a
14136        // `Caixa { edicao: Some("2026"), .. }` (the canonical
14137        // 4-digit-ASCII-decimal-year form) must pass validate. The
14138        // pair jointly pins the accessor + validate-gate composition:
14139        // any future silent detour that had the accessor return `None`
14140        // on the empty arm (a `.filter(|s| !s.is_empty())` collapse)
14141        // would silently absorb the `EdicaoEmpty` refusal at the
14142        // accessor boundary and the validate gate would accept a
14143        // struct-literal `Caixa { edicao: Some(""), .. }` — the
14144        // composition pin catches that at caixa-core build time.
14145        //
14146        // Peer of the [`Caixa::licenca`] (6d5bc28)
14147        // `validate_licenca_empty_arm_routes_through_accessor`,
14148        // [`Caixa::repositorio`] (cc7332d)
14149        // `validate_repositorio_empty_arm_routes_through_accessor`,
14150        // and [`Caixa::descricao`] (3f16e2f)
14151        // `validate_descricao_empty_arm_routes_through_accessor`
14152        // composition pins on the sibling outer top-level [`Caixa`]
14153        // `Option<&str>` universal-axis surface — same "the validate /
14154        // shape-gate predicate must route through the substrate-
14155        // primitive typed dispatch" discipline extended onto the
14156        // fourth and final outer top-level [`Caixa`] universal-axis
14157        // `Option<&str>`-composition surface, closing the accessor-
14158        // composition family.
14159        let c = caixa_with_edicao(Some(""));
14160        assert!(
14161            matches!(c.validate_edicao(), Err(ManifestError::EdicaoEmpty)),
14162            "validate_edicao must reject edicao == Some(\"\") with \
14163             EdicaoEmpty — the accessor and the validate gate must \
14164             route through the same substrate-primitive typed dispatch \
14165             on the :edicao empty arm",
14166        );
14167        let c = caixa_with_edicao(Some("2026"));
14168        assert!(
14169            c.validate_edicao().is_ok(),
14170            "validate_edicao must accept edicao == Some(\"2026\") \
14171             (the canonical 4-digit-ASCII-decimal-year shape)",
14172        );
14173    }
14174
14175    #[test]
14176    fn edicao_projects_option_str_by_borrow() {
14177        // The by-borrow pin: [`Caixa::edicao`] returns
14178        // `Option<&str>` by borrow — the `&str` borrows the underlying
14179        // `String` storage of the `Option<String>` slot and the
14180        // accessor must not allocate a fresh `String` on every call.
14181        // Peer of the [`Caixa::licenca`] (6d5bc28),
14182        // [`Caixa::repositorio`] (cc7332d), and [`Caixa::descricao`]
14183        // (3f16e2f) by-borrow pins on the peer outer top-level
14184        // [`Caixa`] `Option<&str>`-return axes, and of the
14185        // per-`:placement`
14186        // [`crate::aplicacao::Placement::shard_key`] (7cd2a28) by-
14187        // borrow pin on the peer per-M3-mesh-slot `Option<&str>`-
14188        // return axis, extended onto the fourth and final outer top-
14189        // level [`Caixa`] universal-axis `Option<&str>` shape — the
14190        // accessor's returned `&str` must borrow from `&self` (the
14191        // returned reference's lifetime is tied to `&self`), and
14192        // calling the accessor twice on the same [`Caixa`] must yield
14193        // the same `Option<&str>` verbatim (idempotent, no side
14194        // effects on `&self`).
14195        //
14196        // Pins against a future silent detour that returned an owned
14197        // `Option<String>` (which would type-check but silently
14198        // allocate on every call, breaking the zero-cost projection
14199        // every peer sibling accessor carries), or a one-arm-only
14200        // accessor that returned a saturating value on some sentinel
14201        // input (breaking the pass-through invariant the sibling
14202        // required-scalar accessors carry).
14203        for edicao in [None, Some(""), Some("2026"), Some("2018")] {
14204            let c = caixa_with_edicao(edicao);
14205            let first = c.edicao();
14206            let second = c.edicao();
14207            assert_eq!(
14208                first, second,
14209                "Caixa::edicao must be idempotent — two successive \
14210                 calls on the same &self must return the same \
14211                 Option<&str>",
14212            );
14213            assert_eq!(
14214                first, edicao,
14215                "Caixa::edicao must return :edicao verbatim by \
14216                 borrow — got {first:?}, expected {edicao:?}",
14217            );
14218        }
14219    }
14220
14221    #[test]
14222    fn nome_returns_nome_byte_string_verbatim_across_permutations() {
14223        // The canonical per-`Caixa` `:nome` universal-axis DNS-1123-
14224        // label caixa-identity scalar pin: [`Caixa::nome`] must return
14225        // the `:nome` typed `String` verbatim as `&str`, byte-equal to
14226        // the raw field access across every representative value in
14227        // the accept-set — the canonical `"demo"` template baseline
14228        // (the same `feira init`-scaffolded default the sibling
14229        // `validate_nome_accepts_canonical_template` positive-control
14230        // gate pins), plus every sibling per-typed-slot atom accessor's
14231        // canonical positive-arm byte-string (`"catalog"` per
14232        // [`crate::aplicacao::Membro::nome`], `"cart"` per the peer
14233        // per-`:contratos` `:de`, `"hello-rio"` per the canonical
14234        // `caixa-helm`/`caixa-flux` cross-crate integration-test
14235        // fixture, `"checkout"` per the M3 mesh-slot Aplicacao
14236        // canonical example), plus every past-the-guard sentinel for
14237        // the `NomeEmpty` / `NomeInvalid` / `NomeChartNameBudgetExceeded`
14238        // refusal cases (`""`, `"Bad_Name"`, `"a"` × 56 — 56 bytes fits
14239        // the bare DNS-1123 63-byte cap but overflows the joint
14240        // `lareira-<nome>` chart-name budget the sibling
14241        // [`Caixa::validate_nome_chart_name_budget`] gate closes on).
14242        //
14243        // The past-the-guard sentinels pin the accessor doesn't
14244        // silently absorb the refusal cases into a template-derived
14245        // fallback (a future `.nome().is_empty().then(|| "demo")`
14246        // collapse would silently absorb the `NomeEmpty` refusal at
14247        // the accessor boundary and the validate gate would accept a
14248        // struct-literal `Caixa { nome: "".into(), .. }` — the pin
14249        // catches that at caixa-core build time).
14250        //
14251        // First outer top-level [`Caixa`] `&str`-return required-
14252        // scalar accessor pin — opens the "outer [`Caixa`] `&str`
14253        // required-scalar" projection pattern the sibling per-`Caixa`
14254        // `:versao` future lift folds on. Sibling in shape to the peer
14255        // per-`:membros` [`crate::aplicacao::Membro::nome`] (4a32abf)
14256        // required-`String`-carry accessor pin on the sibling per-
14257        // sub-struct required-axis, extended onto the outer top-level
14258        // [`Caixa`] universal-axis required-`String`-carry axis.
14259        for nome in [
14260            "demo",
14261            "catalog",
14262            "cart",
14263            "hello-rio",
14264            "checkout",
14265            "",
14266            "Bad_Name",
14267            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
14268        ] {
14269            let c = caixa_with_nome(nome);
14270            assert_eq!(
14271                c.nome(),
14272                nome,
14273                "Caixa::nome must return :nome verbatim (got {}, \
14274                 expected {nome})",
14275                c.nome(),
14276            );
14277            assert_eq!(
14278                c.nome(),
14279                c.nome.as_str(),
14280                "Caixa::nome must byte-equal the raw .nome field \
14281                 access across every value in the String accept-set",
14282            );
14283        }
14284    }
14285
14286    #[test]
14287    fn validate_nome_empty_arm_routes_through_accessor() {
14288        // Composition pin: [`Caixa::validate_nome`]'s empty-arm must
14289        // key off [`Caixa::nome`], not the raw `.nome` field access.
14290        // Structurally: a `Caixa { nome: "".into(), .. }` must surface
14291        // the `NomeEmpty` refusal exactly, and the canonical `"demo"`
14292        // template baseline (the peer positive-arm the sibling
14293        // `validate_nome_accepts_canonical_template` gate carves out)
14294        // must pass validate. The pair jointly pins the accessor +
14295        // validate-gate composition: any future silent detour that
14296        // had the accessor return a fresh `"demo"` on the empty arm
14297        // (a `.nome().is_empty().then(|| "demo")` fallback collapse)
14298        // would silently absorb the `NomeEmpty` refusal at the
14299        // accessor boundary and the validate gate would accept a
14300        // struct-literal `Caixa { nome: "".into(), .. }` — the
14301        // composition pin catches that at caixa-core build time.
14302        //
14303        // Peer of the sibling per-`Caixa`
14304        // `validate_licenca_empty_arm_routes_through_accessor` (6d5bc28)
14305        // / `validate_repositorio_empty_arm_routes_through_accessor`
14306        // (cc7332d) / `validate_descricao_empty_arm_routes_through_accessor`
14307        // (3f16e2f) / `validate_edicao_empty_arm_routes_through_accessor`
14308        // (2641cbd) composition pins on the sibling outer top-level
14309        // [`Caixa`] `Option<&str>` axes — same "the validate /
14310        // shape-gate predicate must route through the substrate-
14311        // primitive typed dispatch" discipline extended onto the peer
14312        // outer top-level [`Caixa`] required-`&str` composition axis.
14313        let c = caixa_with_nome("");
14314        assert!(
14315            matches!(c.validate_nome(), Err(ManifestError::NomeEmpty)),
14316            "validate_nome must reject nome == \"\" with NomeEmpty — \
14317             the accessor and the validate gate must route through the \
14318             same substrate-primitive typed dispatch on the :nome \
14319             empty-arm",
14320        );
14321        let c = caixa_with_nome("demo");
14322        assert!(
14323            c.validate_nome().is_ok(),
14324            "validate_nome must accept nome == \"demo\" (the canonical \
14325             DNS-1123-label template baseline)",
14326        );
14327    }
14328
14329    #[test]
14330    fn nome_projects_str_by_borrow() {
14331        // The by-borrow pin: [`Caixa::nome`] returns `&str` by borrow
14332        // — the `&str` borrows the underlying `String` storage of the
14333        // required `nome` slot and the accessor must not allocate a
14334        // fresh `String` on every call. Peer of the [`Caixa::licenca`]
14335        // (6d5bc28) / [`Caixa::repositorio`] (cc7332d) /
14336        // [`Caixa::descricao`] (3f16e2f) / [`Caixa::edicao`] (2641cbd)
14337        // by-borrow pins on the peer outer top-level [`Caixa`]
14338        // `Option<&str>`-return axes, extended onto the first outer
14339        // top-level [`Caixa`] required-`&str`-return axis — the
14340        // accessor's returned `&str` must borrow from `&self` (the
14341        // returned reference's lifetime is tied to `&self`), and
14342        // calling the accessor twice on the same [`Caixa`] must yield
14343        // the same `&str` verbatim (idempotent, no side effects on
14344        // `&self`).
14345        //
14346        // Pins against a future silent detour that returned an owned
14347        // `String` (which would type-check but silently allocate on
14348        // every call, breaking the zero-cost projection every peer
14349        // sibling accessor carries), an accidental
14350        // `.nome.to_lowercase()` detour that returned a fresh
14351        // allocation through an already-DNS-1123-lowercase-only
14352        // string (breaking a future `const fn` regression), or a
14353        // one-arm-only accessor that returned a canonicalized value
14354        // on some sentinel input (breaking the pass-through invariant
14355        // the sibling required-scalar accessors carry).
14356        for nome in ["demo", "catalog", "hello-rio", "checkout"] {
14357            let c = caixa_with_nome(nome);
14358            let first = c.nome();
14359            let second = c.nome();
14360            assert_eq!(
14361                first, second,
14362                "Caixa::nome must be idempotent — two successive calls \
14363                 on the same &self must return the same &str",
14364            );
14365            assert_eq!(
14366                first, nome,
14367                "Caixa::nome must return :nome verbatim by borrow — \
14368                 got {first}, expected {nome}",
14369            );
14370        }
14371    }
14372
14373    #[test]
14374    fn versao_returns_versao_byte_string_verbatim_across_permutations() {
14375        // The canonical per-`Caixa` `:versao` universal-axis SemVer-2
14376        // pinned-version scalar pin: [`Caixa::versao`] must return the
14377        // `:versao` typed `String` verbatim as `&str`, byte-equal to the
14378        // raw `.versao` field access across every representative value
14379        // in the accept-set — the canonical `"0.1.0"` template baseline
14380        // (the same `feira init`-scaffolded default the sibling
14381        // `validate_versao_accepts_canonical_template` positive-control
14382        // gate pins), plus every canonical SemVer-2 shape the sibling
14383        // `validate_versao_accepts_canonical_forms` positive-arm sweep
14384        // covers (`"0.0.0"`, `"1.0.0"`, `"0.2.0-rc.1"`,
14385        // `"1.0.0-alpha.0"`, `"1.0.0+build.42"`, `"1.0.0-rc.1+build.42"`,
14386        // `"10.20.30"`), plus every past-the-guard sentinel for the
14387        // `VersaoEmpty` / `VersaoInvalid` refusal cases (`""` the empty
14388        // arm, `"v0.1.0"` the git-tag-shape-leak footgun, `"0.1"` the
14389        // missing-patch footgun, `"^0.1"` the requirement-shape-leak
14390        // footgun, `"0.1.0.0"` the four-part-Java-convention footgun,
14391        // `"latest"` the docker-tag-shape footgun — the sentinels pin
14392        // the accessor doesn't silently absorb the refusal cases into a
14393        // template-derived fallback like `"0.1.0"`).
14394        //
14395        // The past-the-guard sentinels pin the accessor doesn't silently
14396        // absorb the refusal cases into a template-derived fallback (a
14397        // future `.versao().is_empty().then(|| "0.1.0")` collapse would
14398        // silently absorb the `VersaoEmpty` refusal at the accessor
14399        // boundary and the validate gate would accept a struct-literal
14400        // `Caixa { versao: "".into(), .. }` — the pin catches that at
14401        // caixa-core build time).
14402        //
14403        // Second outer top-level [`Caixa`] `&str`-return required-scalar
14404        // accessor pin — folds on the "outer [`Caixa`] `&str` required-
14405        // scalar" projection pattern the sibling per-`Caixa`
14406        // [`Caixa::nome`] (e6b7d97) opened. Sibling in shape to the peer
14407        // per-`:membros` [`crate::aplicacao::Membro::versao_requirement`]
14408        // (4127bb6) / per-`:children`
14409        // [`crate::supervisor::ChildSpec::versao_requirement`] (2c053c8)
14410        // / per-`:upgrade-from`
14411        // [`crate::UpgradeFromEntry::prior_versao`] (75d27a8) per-sub-
14412        // struct `:versao`-shaped `&str`-return accessor pins on the
14413        // sibling per-typed-slot version-carrier axes, extended onto the
14414        // second outer top-level [`Caixa`] universal-axis required-
14415        // `String`-carry axis so the two universal-axis identity-
14416        // carrying scalars every `defcaixa` form supplies (`:nome` +
14417        // `:versao`) share the same "one typed dispatch per axis" pin
14418        // discipline.
14419        for versao in [
14420            "0.1.0",
14421            "0.0.0",
14422            "1.0.0",
14423            "0.2.0-rc.1",
14424            "1.0.0-alpha.0",
14425            "1.0.0+build.42",
14426            "1.0.0-rc.1+build.42",
14427            "10.20.30",
14428            "",
14429            "v0.1.0",
14430            "0.1",
14431            "^0.1",
14432            "0.1.0.0",
14433            "latest",
14434        ] {
14435            let c = caixa_with_versao(versao);
14436            assert_eq!(
14437                c.versao(),
14438                versao,
14439                "Caixa::versao must return :versao verbatim (got {}, \
14440                 expected {versao})",
14441                c.versao(),
14442            );
14443            assert_eq!(
14444                c.versao(),
14445                c.versao.as_str(),
14446                "Caixa::versao must byte-equal the raw .versao field \
14447                 access across every value in the String accept-set",
14448            );
14449        }
14450    }
14451
14452    #[test]
14453    fn validate_versao_empty_arm_routes_through_accessor() {
14454        // Composition pin: [`Caixa::validate_versao`]'s empty-arm gate
14455        // must key off [`Caixa::versao`], not the raw `.versao` field
14456        // access. Structurally: a `Caixa { versao: "".into(), .. }` must
14457        // surface the `VersaoEmpty` refusal exactly, and the canonical
14458        // `"0.1.0"` template baseline (the peer positive-arm the sibling
14459        // `validate_versao_accepts_canonical_template` gate carves out)
14460        // must pass validate. The pair jointly pins the accessor +
14461        // validate-gate composition: any future silent detour that had
14462        // the accessor return a fresh `"0.1.0"` on the empty arm
14463        // (a `.versao().is_empty().then(|| "0.1.0")` fallback collapse)
14464        // would silently absorb the `VersaoEmpty` refusal at the
14465        // accessor boundary and the validate gate would accept a
14466        // struct-literal `Caixa { versao: "".into(), .. }` — the
14467        // composition pin catches that at caixa-core build time.
14468        //
14469        // Peer of the sibling per-`Caixa`
14470        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97)
14471        // composition pin on the sibling outer top-level [`Caixa`]
14472        // required-`&str` universal-axis surface — same "the validate /
14473        // shape-gate predicate must route through the substrate-
14474        // primitive typed dispatch" discipline extended onto the peer
14475        // outer top-level [`Caixa`] required-`&str` universal-axis
14476        // pinned-version composition axis, closing the second
14477        // coordinate of the "one canonical typed dispatch per per-Caixa
14478        // required-`&str` universal-axis" discipline.
14479        let c = caixa_with_versao("");
14480        assert!(
14481            matches!(c.validate_versao(), Err(ManifestError::VersaoEmpty)),
14482            "validate_versao must reject versao == \"\" with VersaoEmpty — \
14483             the accessor and the validate gate must route through the \
14484             same substrate-primitive typed dispatch on the :versao \
14485             empty-arm",
14486        );
14487        let c = caixa_with_versao("0.1.0");
14488        assert!(
14489            c.validate_versao().is_ok(),
14490            "validate_versao must accept versao == \"0.1.0\" (the \
14491             canonical SemVer-2 template baseline)",
14492        );
14493    }
14494
14495    #[test]
14496    fn versao_projects_str_by_borrow() {
14497        // The by-borrow pin: [`Caixa::versao`] returns `&str` by borrow
14498        // — the `&str` borrows the underlying `String` storage of the
14499        // required `versao` slot and the accessor must not allocate a
14500        // fresh `String` on every call. Peer of the [`Caixa::nome`]
14501        // (e6b7d97) by-borrow pin on the sibling outer top-level
14502        // [`Caixa`] required-`&str`-return axis, extended onto the
14503        // second outer top-level [`Caixa`] required-`&str`-return
14504        // universal-axis pinned-version surface — the accessor's
14505        // returned `&str` must borrow from `&self` (the returned
14506        // reference's lifetime is tied to `&self`), and calling the
14507        // accessor twice on the same [`Caixa`] must yield the same
14508        // `&str` verbatim (idempotent, no side effects on `&self`).
14509        //
14510        // Pins against a future silent detour that returned an owned
14511        // `String` (which would type-check but silently allocate on
14512        // every call, breaking the zero-cost projection every peer
14513        // sibling accessor carries), an accidental
14514        // `semver::Version::parse(&self.versao).unwrap().to_string()`
14515        // detour that returned a canonicalized fresh allocation through
14516        // an already-canonical byte-string (breaking a future `const fn`
14517        // regression and silently absorbing the `VersaoInvalid` refusal
14518        // at the accessor boundary), or a one-arm-only accessor that
14519        // returned a canonicalized value on some sentinel input
14520        // (breaking the pass-through invariant the sibling required-
14521        // scalar accessors carry).
14522        for versao in ["0.1.0", "1.0.0", "0.2.0-rc.1", "1.0.0+build.42"] {
14523            let c = caixa_with_versao(versao);
14524            let first = c.versao();
14525            let second = c.versao();
14526            assert_eq!(
14527                first, second,
14528                "Caixa::versao must be idempotent — two successive \
14529                 calls on the same &self must return the same &str",
14530            );
14531            assert_eq!(
14532                first, versao,
14533                "Caixa::versao must return :versao verbatim by borrow \
14534                 — got {first}, expected {versao}",
14535            );
14536        }
14537    }
14538
14539    fn caixa_with_kind(kind: CaixaKind) -> Caixa {
14540        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
14541        c.kind = kind;
14542        c
14543    }
14544
14545    #[test]
14546    fn kind_returns_kind_variant_verbatim_across_permutations() {
14547        // The canonical per-`Caixa` `:kind` universal-axis closed-set-
14548        // enum discriminant pin: [`Caixa::kind`] must return the `:kind`
14549        // typed [`CaixaKind`] variant verbatim by `Copy`, byte-equal to
14550        // the raw `.kind` field access across every variant in the
14551        // closed accept-set (`Biblioteca` — the library kind that
14552        // exports lisp forms; `Binario` — the nix-built executable kind
14553        // under `exe/`; `Servico` — the wasm-component daemon kind
14554        // under `servicos/`; `Supervisor` — the OTP-shaped hierarchical
14555        // reconciliation kind; `Aplicacao` — the M3 typed-mesh
14556        // composition kind).
14557        //
14558        // Pins against a future silent detour that re-derived the kind
14559        // from a peer axis (an accidental fallback to
14560        // `if !servicos.is_empty() { Servico } else if
14561        // !membros.is_empty() { Aplicacao } else { Biblioteca }`
14562        // collapse that read the code-surface / mesh-slot columns into
14563        // the kind discriminator), a variant remap the operator
14564        // authors on one consumer without the other, or a stale-derive
14565        // detour that substituted [`CaixaKind::Biblioteca`] as the
14566        // default when the field held any other variant (which would
14567        // silently collapse the distinction between "author explicitly
14568        // declared `:kind Servico`" and "author declared any other
14569        // kind" every downstream renderer-dispatch site depends on).
14570        //
14571        // First outer top-level [`Caixa`] `Copy`-return required-enum-
14572        // discriminant accessor pin — opens the "outer [`Caixa`]
14573        // `Copy`-return required-discriminant" projection pattern.
14574        // Sibling in shape to the peer per-`:supervisor`
14575        // [`crate::supervisor::SupervisorSpec::estrategia`] (eafb619),
14576        // per-`:placement` [`crate::aplicacao::Placement::estrategia`]
14577        // (921fe1b), and per-`:children`
14578        // [`crate::supervisor::ChildSpec::restart`] (dfb4a81)
14579        // `Copy`-return closed-set-enum discriminant accessor pins on
14580        // the sibling nested-spec typed-slot discriminator axes,
14581        // extended here to the outer top-level [`Caixa`] universal-
14582        // axis surface.
14583        for kind in [
14584            CaixaKind::Biblioteca,
14585            CaixaKind::Binario,
14586            CaixaKind::Servico,
14587            CaixaKind::Supervisor,
14588            CaixaKind::Aplicacao,
14589        ] {
14590            let c = caixa_with_kind(kind);
14591            assert_eq!(
14592                c.kind(),
14593                kind,
14594                "Caixa::kind must return :kind verbatim (got {:?}, \
14595                 expected {kind:?})",
14596                c.kind(),
14597            );
14598            assert_eq!(
14599                c.kind(),
14600                c.kind,
14601                "Caixa::kind accessor and .kind field access must \
14602                 byte-equal — the accessor is the substrate-primitive \
14603                 typed dispatch every downstream kind-gate consumer \
14604                 must route through",
14605            );
14606        }
14607    }
14608
14609    #[test]
14610    fn require_kind_reads_through_lifted_kind_accessor() {
14611        // Two-consumer coherence pin: the [`crate::render::require_kind`]
14612        // entry-gate predicate (the canonical two-line
14613        // `require_kind(caixa, Servico)?` prelude every per-Servico /
14614        // per-Aplicacao renderer runs at its entry-point) and the
14615        // sibling [`crate::render::KindMismatch`] error carrier's
14616        // `actual:` field (which names the offending caixa's variant
14617        // in the diagnostic) must both key off the lifted accessor, so
14618        // any future rebrand on the typed slot's reader shape lands at
14619        // exactly one place. Pins the two-site coherence by exercising
14620        // every off-diagonal `(actual, expected)` pair across the
14621        // closed accept-set — the `KindMismatch { actual, expected }`
14622        // surfaced on the mismatch arm must byte-equal the pair the
14623        // accessor returns for each side.
14624        //
14625        // Peer of the sibling per-`:placement`
14626        // `validate_placement_reads_through_lifted_estrategia_accessor`
14627        // (921fe1b) two-arm consumer-coherence pin on the M3 mesh-slot
14628        // `Copy`-return discriminant axis — same "the entry-gate
14629        // predicate and the error carrier's `actual:` field must route
14630        // through the substrate-primitive typed dispatch" discipline
14631        // extended onto the outer top-level [`Caixa`] universal-axis
14632        // discriminant surface.
14633        for expected in [
14634            CaixaKind::Biblioteca,
14635            CaixaKind::Binario,
14636            CaixaKind::Servico,
14637            CaixaKind::Supervisor,
14638            CaixaKind::Aplicacao,
14639        ] {
14640            for actual in [
14641                CaixaKind::Biblioteca,
14642                CaixaKind::Binario,
14643                CaixaKind::Servico,
14644                CaixaKind::Supervisor,
14645                CaixaKind::Aplicacao,
14646            ] {
14647                let c = caixa_with_kind(actual);
14648                let result = crate::render::require_kind(&c, expected);
14649                if expected == actual {
14650                    assert!(
14651                        result.is_ok(),
14652                        "require_kind must accept when actual == expected \
14653                         (actual={actual:?}, expected={expected:?})",
14654                    );
14655                } else {
14656                    let err = result.expect_err("require_kind must reject when actual != expected");
14657                    assert_eq!(
14658                        err.actual,
14659                        c.kind(),
14660                        "KindMismatch.actual must byte-equal Caixa::kind() \
14661                         — the error carrier's `actual:` field reads \
14662                         through the lifted accessor",
14663                    );
14664                    assert_eq!(
14665                        err.expected, expected,
14666                        "KindMismatch.expected must byte-equal the \
14667                         expected variant passed to require_kind",
14668                    );
14669                }
14670            }
14671        }
14672    }
14673
14674    #[test]
14675    fn aplicacao_view_kind_gate_routes_through_accessor() {
14676        // Composition pin: [`Caixa::aplicacao_view`]'s kind-gate arm
14677        // must key off [`Caixa::kind`], not the raw `.kind` field
14678        // access. Structurally: a `Caixa { kind: X, .. }` for any
14679        // non-`Aplicacao` variant must fold to `None` on the
14680        // `aplicacao_view` composer (the "kind mismatch → no typed
14681        // view" contract every downstream Aplicacao consumer keys off
14682        // via `?`), and a `Caixa { kind: Aplicacao, .. }` must fold to
14683        // `Some(_)`. The pair jointly pins the accessor + view-gate
14684        // composition: any future silent detour that had the accessor
14685        // return a fresh [`CaixaKind::Aplicacao`] on some sentinel
14686        // input would silently absorb the kind-mismatch case at the
14687        // accessor boundary and every per-Aplicacao renderer would
14688        // silently render a non-Aplicacao caixa's mesh slots — the
14689        // composition pin catches that at caixa-core build time.
14690        //
14691        // Peer of the sibling per-`Caixa`
14692        // `validate_nome_empty_arm_routes_through_accessor` (e6b7d97) /
14693        // `validate_versao_empty_arm_routes_through_accessor` (20c0539)
14694        // composition pins on the sibling outer top-level [`Caixa`]
14695        // required-`&str` universal-axis surfaces — same "the
14696        // composer / validate gate must route through the substrate-
14697        // primitive typed dispatch" discipline extended onto the
14698        // outer top-level [`Caixa`] `Copy`-return required-
14699        // discriminant composition axis.
14700        for kind in [
14701            CaixaKind::Biblioteca,
14702            CaixaKind::Binario,
14703            CaixaKind::Servico,
14704            CaixaKind::Supervisor,
14705        ] {
14706            let c = caixa_with_kind(kind);
14707            assert!(
14708                c.aplicacao_view().is_none(),
14709                "aplicacao_view must return None on non-Aplicacao \
14710                 kind {kind:?} — the composer's kind-gate must route \
14711                 through Caixa::kind()",
14712            );
14713        }
14714        let c = caixa_with_kind(CaixaKind::Aplicacao);
14715        assert!(
14716            c.aplicacao_view().is_some(),
14717            "aplicacao_view must return Some on kind Aplicacao — \
14718             the composer's kind-gate must accept the matching arm \
14719             through Caixa::kind()",
14720        );
14721    }
14722
14723    #[test]
14724    fn supervisor_view_kind_gate_routes_through_accessor() {
14725        // Composition pin (mirror of the sibling
14726        // `aplicacao_view_kind_gate_routes_through_accessor` on the
14727        // second `_view` composer): [`Caixa::supervisor_view`]'s kind-
14728        // gate arm must key off [`Caixa::kind`], not the raw `.kind`
14729        // field access. A `Caixa { kind: X, .. }` for any non-
14730        // `Supervisor` variant must fold to `None` on the
14731        // `supervisor_view` composer, and a `Caixa { kind:
14732        // Supervisor, .. }` must fold to `Some(_)`. Same peer
14733        // composition pin discipline on the second `_view` composer
14734        // axis.
14735        for kind in [
14736            CaixaKind::Biblioteca,
14737            CaixaKind::Binario,
14738            CaixaKind::Servico,
14739            CaixaKind::Aplicacao,
14740        ] {
14741            let c = caixa_with_kind(kind);
14742            assert!(
14743                c.supervisor_view().is_none(),
14744                "supervisor_view must return None on non-Supervisor \
14745                 kind {kind:?} — the composer's kind-gate must route \
14746                 through Caixa::kind()",
14747            );
14748        }
14749        let mut c = caixa_with_kind(CaixaKind::Supervisor);
14750        // A Supervisor caixa needs a strategy + at least one child to
14751        // fold to a Some(_) that also validates; the composer itself
14752        // requires only the kind arm, so bare kind flip is enough to
14753        // pin the `Some(_)` return, but we populate the minimum
14754        // supervisor shape so a future strengthening of the composer
14755        // to reject an empty spec doesn't false-positive this pin.
14756        c.estrategia = Some(crate::supervisor::RestartStrategy::OneForOne);
14757        c.children = vec![crate::supervisor::ChildSpec {
14758            caixa: "child".into(),
14759            versao: "^0.1".into(),
14760            restart: crate::supervisor::RestartPolicy::Permanent,
14761        }];
14762        assert!(
14763            c.supervisor_view().is_some(),
14764            "supervisor_view must return Some on kind Supervisor — \
14765             the composer's kind-gate must accept the matching arm \
14766             through Caixa::kind()",
14767        );
14768    }
14769
14770    #[test]
14771    fn kind_projects_by_copy() {
14772        // The by-`Copy` pin: [`Caixa::kind`] returns a fresh
14773        // [`CaixaKind`] by `Copy` — the accessor must not borrow from
14774        // `&self` (the returned value is owned, `Copy`-projected from
14775        // the underlying [`CaixaKind`] storage; two calls on the same
14776        // [`Caixa`] must yield byte-equal values). Peer of the peer
14777        // per-`:placement` `Placement::estrategia` / per-`:supervisor`
14778        // `SupervisorSpec::estrategia` / per-`:children`
14779        // `ChildSpec::restart` `Copy`-return discriminant accessor
14780        // pins on the sibling nested-spec typed-slot discriminator
14781        // axes, extended onto the first outer top-level [`Caixa`]
14782        // required-`Copy`-return axis — pins against a future silent
14783        // detour that returned `&CaixaKind` (which would type-check
14784        // but silently constrain every consumer's callsite to a
14785        // borrow-shaped dispatch, breaking the zero-cost `Copy`
14786        // projection every peer sibling accessor carries).
14787        for kind in [
14788            CaixaKind::Biblioteca,
14789            CaixaKind::Binario,
14790            CaixaKind::Servico,
14791            CaixaKind::Supervisor,
14792            CaixaKind::Aplicacao,
14793        ] {
14794            let c = caixa_with_kind(kind);
14795            let first: CaixaKind = c.kind();
14796            let second: CaixaKind = c.kind();
14797            assert_eq!(
14798                first, second,
14799                "Caixa::kind must be idempotent — two successive \
14800                 calls on the same &self must return the same \
14801                 CaixaKind variant",
14802            );
14803            assert_eq!(
14804                first, kind,
14805                "Caixa::kind must return :kind verbatim by Copy — \
14806                 got {first:?}, expected {kind:?}",
14807            );
14808        }
14809    }
14810
14811    // ── Caixa::autores — outer top-level &[T] slice accessor ──────────
14812
14813    #[test]
14814    fn autores_returns_autores_slice_verbatim_across_permutations() {
14815        // The canonical per-`Caixa` `:autores` universal-axis maintainer-
14816        // name-list slice pin: [`Caixa::autores`] must return the
14817        // `:autores` typed [`Vec<String>`] list verbatim as a
14818        // `&[String]`, byte-equal to the raw `self.autores.as_slice()`
14819        // access across every representative value in the accept-set —
14820        // `[]` (the "no maintainers declared" arm every existing
14821        // fixture without an `:autores` line carries), `[""]` (a past-
14822        // the-guard sentinel that pins the accessor doesn't perform a
14823        // silent `[""] → []` collapse on the empty-entry arm — validate
14824        // rejects `[""]` through `AutorEmpty` but the accessor must
14825        // ship the raw slot verbatim so a validate-time gate regression
14826        // surfaces at the caixa-helm emit boundary rather than being
14827        // silently absorbed into a maintainer-drop), `["pleme-io"]` (the
14828        // canonical single-maintainer form every `feira init` template
14829        // scaffolds), `["alice", "bob"]` (a canonical multi-maintainer
14830        // form), `["alice <alice@example.com>", "bob <bob@example.com>"]`
14831        // (the canonical RFC-5322 `<name> <email>` form the
14832        // `is_chart_maintainer_name_shape` predicate accepts), and
14833        // `["pleme-io", "pleme-io"]` (a past-the-guard duplicate
14834        // sentinel — validate rejects through `AutorDuplicate` but the
14835        // accessor must ship the raw slot verbatim).
14836        //
14837        // First outer top-level [`Caixa`] `&[T]`-return slice accessor
14838        // pin on the substrate primitive — opens the "outer [`Caixa`]
14839        // `&[T]` slice" projection pattern the sibling per-`Caixa`
14840        // `:etiquetas` / `:deps` / `:deps-dev` / `:exe` / `:bibliotecas`
14841        // / `:servicos` / `:upgrade-from` / `:children` future lifts
14842        // fold on. Sibling in shape to the peer per-`:supervisor`
14843        // [`crate::supervisor::SupervisorSpec::children`] (bc92bce),
14844        // per-`:placement` [`crate::aplicacao::Placement::clusters`]
14845        // (a6e18d7), per-`:membros`
14846        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36),
14847        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
14848        // (0dcc926), and per-`:upgrade-from :instructions`
14849        // [`crate::upgrade::UpgradeFromEntry::instructions`] (0137e5a)
14850        // `&[T]`-return slice accessor pins on the sibling per-M2 /
14851        // per-M3 typed-slot list axes, extended onto the outer top-
14852        // level [`Caixa`] universal-axis surface. Pins against a future
14853        // silent detour that returned an owned `Vec<String>` (which
14854        // would type-check but silently clone on every accessor call,
14855        // breaking the zero-cost projection every peer sibling slice
14856        // accessor carries), a `[""] → []` collapse (which would
14857        // silently absorb the `AutorEmpty` refusal case at the accessor
14858        // boundary), or a `["a", "a"] → ["a"]` dedup collapse (which
14859        // would silently absorb the `AutorDuplicate` refusal case at
14860        // the accessor boundary and the caixa-helm `maintainers:` fold
14861        // would silently render a dedupped list on a struct-literal
14862        // `Caixa { autores: vec!["a".into(), "a".into()], .. }`).
14863        for autores in [
14864            vec![],
14865            vec![""],
14866            vec!["pleme-io"],
14867            vec!["alice", "bob"],
14868            vec!["alice <alice@example.com>", "bob <bob@example.com>"],
14869            vec!["pleme-io", "pleme-io"],
14870        ] {
14871            let c = caixa_with_autores(autores.clone());
14872            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
14873            assert_eq!(
14874                c.autores(),
14875                expected.as_slice(),
14876                "Caixa::autores must return :autores verbatim (got {:?}, \
14877                 expected {expected:?})",
14878                c.autores(),
14879            );
14880            assert_eq!(
14881                c.autores(),
14882                c.autores.as_slice(),
14883                "Caixa::autores must byte-equal the raw \
14884                 `self.autores.as_slice()` field access across every \
14885                 value in the Vec<String> accept-set",
14886            );
14887        }
14888    }
14889
14890    #[test]
14891    fn validate_autores_empty_entry_arm_routes_through_accessor() {
14892        // Composition pin: [`Caixa::validate_autores`]'s per-entry
14893        // empty-arm gate must key off [`Caixa::autores`], not the raw
14894        // `&self.autores` field-borrow walk. Structurally: a
14895        // `Caixa { autores: vec!["".into()], .. }` must surface the
14896        // `AutorEmpty` refusal exactly, and a
14897        // `Caixa { autores: vec!["pleme-io".into()], .. }` (the
14898        // canonical single-maintainer form) must pass validate. The
14899        // pair jointly pins the accessor + validate-gate composition:
14900        // any future silent detour that had the accessor return an
14901        // empty slice on the `[""]` arm (a
14902        // `.iter().filter(|s| !s.is_empty()).collect()` collapse)
14903        // would silently absorb the `AutorEmpty` refusal at the
14904        // accessor boundary and the validate gate would accept a
14905        // struct-literal `Caixa { autores: vec!["".into()], .. }` —
14906        // the composition pin catches that at caixa-core build time.
14907        //
14908        // Peer of the per-`Caixa` [`Caixa::validate_licenca`] (6d5bc28)
14909        // accessor-composition pin
14910        // (`validate_licenca_empty_arm_routes_through_accessor`) on the
14911        // sibling `Option<&str>`-composition axis and the
14912        // per-`:politicas :circuit-breaker`
14913        // [`crate::aplicacao::CircuitBreaker::max_failures`] (3a74062)
14914        // accessor-composition pin
14915        // (`validate_politicas_max_failures_zero_floor_arm_routes_through_accessor`)
14916        // on the sibling required-`u32`-composition axis — same "the
14917        // validate / shape-gate predicate must route through the
14918        // substrate-primitive typed dispatch" discipline extended onto
14919        // the outer top-level [`Caixa`] universal-axis `&[T]`-
14920        // composition surface.
14921        let c = caixa_with_autores(vec![""]);
14922        assert!(
14923            matches!(c.validate_autores(), Err(ManifestError::AutorEmpty)),
14924            "validate_autores must reject autores == vec![\"\"] with \
14925             AutorEmpty — the accessor and the validate gate must \
14926             route through the same substrate-primitive typed dispatch \
14927             on the :autores per-entry empty arm",
14928        );
14929        let c = caixa_with_autores(vec!["pleme-io"]);
14930        assert!(
14931            c.validate_autores().is_ok(),
14932            "validate_autores must accept autores == vec![\"pleme-io\"] \
14933             (the canonical single-maintainer shape every `feira init` \
14934             template scaffolds)",
14935        );
14936    }
14937
14938    #[test]
14939    fn autores_projects_slice_by_borrow() {
14940        // The by-borrow pin: [`Caixa::autores`] returns `&[String]` by
14941        // borrow — the returned slice borrows the underlying
14942        // `Vec<String>` storage of the `:autores` slot and the
14943        // accessor must not clone the backing `Vec` on every call.
14944        // Peer of the per-`:membros`
14945        // [`crate::aplicacao::AplicacaoSpec::membros`] (6c77e36) /
14946        // per-`:contratos` [`crate::aplicacao::AplicacaoSpec::contratos`]
14947        // (0dcc926) / per-`:placement`
14948        // [`crate::aplicacao::Placement::clusters`] (a6e18d7) /
14949        // per-`:supervisor` [`crate::supervisor::SupervisorSpec::children`]
14950        // (bc92bce) by-borrow pins on the sibling per-M2 / per-M3
14951        // typed-slot `&[T]`-return axes, extended onto the outer top-
14952        // level [`Caixa`] universal-axis `&[String]` shape — the
14953        // accessor's returned slice must borrow from `&self` (the
14954        // returned reference's lifetime is tied to `&self`), and
14955        // calling the accessor twice on the same [`Caixa`] must yield
14956        // slices that are pointer-equal (the underlying byte-buffer is
14957        // the storage `Vec`'s allocation, not a fresh copy) as well as
14958        // value-equal (idempotent, no side effects on `&self`).
14959        //
14960        // Pins against a future silent detour that returned an owned
14961        // `Vec<String>` (which would type-check but silently clone on
14962        // every call, breaking the zero-cost projection every peer
14963        // sibling slice accessor carries), a `&Vec<String>` return
14964        // (which would leak the backing `Vec`'s grow/push/reserve
14965        // surface no downstream consumer reaches for), or a one-arm-
14966        // only accessor that returned a saturating value on some
14967        // sentinel input (breaking the pass-through invariant the
14968        // sibling slice accessors carry).
14969        for autores in [
14970            vec![],
14971            vec!["pleme-io"],
14972            vec!["alice", "bob"],
14973            vec!["pleme-io", "pleme-io"],
14974        ] {
14975            let c = caixa_with_autores(autores.clone());
14976            let expected: Vec<String> = autores.iter().map(|s| (*s).to_string()).collect();
14977            let first = c.autores();
14978            let second = c.autores();
14979            assert_eq!(
14980                first, second,
14981                "Caixa::autores must be idempotent — two successive \
14982                 calls on the same &self must return the same \
14983                 &[String]",
14984            );
14985            assert_eq!(
14986                first.as_ptr(),
14987                second.as_ptr(),
14988                "Caixa::autores must borrow the underlying Vec<String> \
14989                 storage — two successive calls must return slices \
14990                 with the same backing pointer (a fresh Vec<String> \
14991                 clone would change the pointer on every call)",
14992            );
14993            assert_eq!(
14994                first,
14995                expected.as_slice(),
14996                "Caixa::autores must return :autores verbatim by \
14997                 borrow — got {first:?}, expected {expected:?}",
14998            );
14999        }
15000    }
15001
15002    // ── Caixa::etiquetas — outer top-level &[T] slice accessor ────────
15003
15004    #[test]
15005    fn etiquetas_returns_etiquetas_slice_verbatim_across_permutations() {
15006        // The canonical per-`Caixa` `:etiquetas` universal-axis
15007        // registry-search-tag-list slice pin: [`Caixa::etiquetas`] must
15008        // return the `:etiquetas` typed [`Vec<String>`] list verbatim
15009        // as a `&[String]`, byte-equal to the raw
15010        // `self.etiquetas.as_slice()` access across every representative
15011        // value in the accept-set — `[]` (the "no tags declared" arm
15012        // every existing fixture without an `:etiquetas` line carries),
15013        // `[""]` (a past-the-guard sentinel that pins the accessor
15014        // doesn't perform a silent `[""] → []` collapse on the empty-
15015        // entry arm — validate rejects `[""]` through `EtiquetaEmpty`
15016        // but the accessor must ship the raw slot verbatim so a
15017        // validate-time gate regression surfaces at the caixa-helm emit
15018        // boundary rather than being silently absorbed into a keyword-
15019        // drop), `["demo"]` (the canonical single-tag form every
15020        // `feira init` template scaffolds), `["example", "aplicacao",
15021        // "mesh", "ecommerce", "demo"]` (the canonical multi-tag form
15022        // the checkout-aplicacao fixture emits), and `["demo", "demo"]`
15023        // (a past-the-guard duplicate sentinel — validate rejects
15024        // through `EtiquetaDuplicate` but the accessor must ship the
15025        // raw slot verbatim so the caixa-helm `BTreeSet::collect` dedup
15026        // at chart-render time isn't silently promoted into the
15027        // accessor boundary and struct-literal
15028        // `Caixa { etiquetas: vec!["demo".into(), "demo".into()], .. }`
15029        // fixtures continue to expose the duplicate at the accessor).
15030        //
15031        // Second outer top-level [`Caixa`] `&[T]`-return slice accessor
15032        // pin on the substrate primitive — folds on the "outer
15033        // [`Caixa`] `&[T]` slice" projection pattern
15034        // `autores_returns_autores_slice_verbatim_across_permutations`
15035        // (b5d813f) opened, sibling in shape and idiom. Pins against a
15036        // future silent detour that returned an owned `Vec<String>`
15037        // (which would type-check but silently clone on every accessor
15038        // call, breaking the zero-cost projection every peer sibling
15039        // slice accessor carries), a `[""] → []` collapse (which would
15040        // silently absorb the `EtiquetaEmpty` refusal case at the
15041        // accessor boundary), or a `["a", "a"] → ["a"]` dedup collapse
15042        // (which would silently absorb the `EtiquetaDuplicate` refusal
15043        // case at the accessor boundary — the caixa-helm chart-render
15044        // `BTreeSet::collect` dedup is downstream of the accessor and
15045        // must not be silently promoted into it).
15046        for etiquetas in [
15047            vec![],
15048            vec![""],
15049            vec!["demo"],
15050            vec!["example", "aplicacao", "mesh", "ecommerce", "demo"],
15051            vec!["demo", "demo"],
15052        ] {
15053            let c = caixa_with_etiquetas(etiquetas.clone());
15054            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
15055            assert_eq!(
15056                c.etiquetas(),
15057                expected.as_slice(),
15058                "Caixa::etiquetas must return :etiquetas verbatim (got \
15059                 {:?}, expected {expected:?})",
15060                c.etiquetas(),
15061            );
15062            assert_eq!(
15063                c.etiquetas(),
15064                c.etiquetas.as_slice(),
15065                "Caixa::etiquetas must byte-equal the raw \
15066                 `self.etiquetas.as_slice()` field access across every \
15067                 value in the Vec<String> accept-set",
15068            );
15069        }
15070    }
15071
15072    #[test]
15073    fn validate_etiquetas_empty_entry_arm_routes_through_accessor() {
15074        // Composition pin: [`Caixa::validate_etiquetas`]'s per-entry
15075        // empty-arm gate must key off [`Caixa::etiquetas`], not the raw
15076        // `&self.etiquetas` field-borrow walk. Structurally: a
15077        // `Caixa { etiquetas: vec!["".into()], .. }` must surface the
15078        // `EtiquetaEmpty` refusal exactly, and a
15079        // `Caixa { etiquetas: vec!["demo".into()], .. }` (the canonical
15080        // single-tag form) must pass validate. The pair jointly pins
15081        // the accessor + validate-gate composition: any future silent
15082        // detour that had the accessor return an empty slice on the
15083        // `[""]` arm (a
15084        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
15085        // silently absorb the `EtiquetaEmpty` refusal at the accessor
15086        // boundary and the validate gate would accept a struct-literal
15087        // `Caixa { etiquetas: vec!["".into()], .. }` — the composition
15088        // pin catches that at caixa-core build time.
15089        //
15090        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
15091        // through_accessor` (b5d813f) accessor-composition pin on the
15092        // sibling `&[T]`-composition axis — same "the validate / shape-
15093        // gate predicate must route through the substrate-primitive
15094        // typed dispatch" discipline extended onto the sibling outer
15095        // top-level [`Caixa`] `&[T]`-composition surface.
15096        let c = caixa_with_etiquetas(vec![""]);
15097        assert!(
15098            matches!(c.validate_etiquetas(), Err(ManifestError::EtiquetaEmpty)),
15099            "validate_etiquetas must reject etiquetas == vec![\"\"] \
15100             with EtiquetaEmpty — the accessor and the validate gate \
15101             must route through the same substrate-primitive typed \
15102             dispatch on the :etiquetas per-entry empty arm",
15103        );
15104        let c = caixa_with_etiquetas(vec!["demo"]);
15105        assert!(
15106            c.validate_etiquetas().is_ok(),
15107            "validate_etiquetas must accept etiquetas == vec![\"demo\"] \
15108             (the canonical single-tag shape every `feira init` \
15109             template scaffolds)",
15110        );
15111    }
15112
15113    #[test]
15114    fn etiquetas_projects_slice_by_borrow() {
15115        // The by-borrow pin: [`Caixa::etiquetas`] returns `&[String]`
15116        // by borrow — the returned slice borrows the underlying
15117        // `Vec<String>` storage of the `:etiquetas` slot and the
15118        // accessor must not clone the backing `Vec` on every call.
15119        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15120        // (b5d813f) by-borrow pin on the sibling outer top-level
15121        // [`Caixa`] `&[String]`-return axis — the accessor's returned
15122        // slice must borrow from `&self` (the returned reference's
15123        // lifetime is tied to `&self`), and calling the accessor twice
15124        // on the same [`Caixa`] must yield slices that are pointer-
15125        // equal (the underlying byte-buffer is the storage `Vec`'s
15126        // allocation, not a fresh copy) as well as value-equal
15127        // (idempotent, no side effects on `&self`).
15128        //
15129        // Pins against a future silent detour that returned an owned
15130        // `Vec<String>` (which would type-check but silently clone on
15131        // every call, breaking the zero-cost projection every peer
15132        // sibling slice accessor carries), a `&Vec<String>` return
15133        // (which would leak the backing `Vec`'s grow/push/reserve
15134        // surface no downstream consumer reaches for), or a one-arm-
15135        // only accessor that returned a saturating value on some
15136        // sentinel input (breaking the pass-through invariant the
15137        // sibling slice accessors carry).
15138        for etiquetas in [
15139            vec![],
15140            vec!["demo"],
15141            vec!["example", "aplicacao", "mesh"],
15142            vec!["demo", "demo"],
15143        ] {
15144            let c = caixa_with_etiquetas(etiquetas.clone());
15145            let expected: Vec<String> = etiquetas.iter().map(|s| (*s).to_string()).collect();
15146            let first = c.etiquetas();
15147            let second = c.etiquetas();
15148            assert_eq!(
15149                first, second,
15150                "Caixa::etiquetas must be idempotent — two successive \
15151                 calls on the same &self must return the same \
15152                 &[String]",
15153            );
15154            assert_eq!(
15155                first.as_ptr(),
15156                second.as_ptr(),
15157                "Caixa::etiquetas must borrow the underlying \
15158                 Vec<String> storage — two successive calls must \
15159                 return slices with the same backing pointer (a fresh \
15160                 Vec<String> clone would change the pointer on every \
15161                 call)",
15162            );
15163            assert_eq!(
15164                first,
15165                expected.as_slice(),
15166                "Caixa::etiquetas must return :etiquetas verbatim by \
15167                 borrow — got {first:?}, expected {expected:?}",
15168            );
15169        }
15170    }
15171
15172    // ── Caixa::bibliotecas — outer top-level &[T] slice accessor ──────
15173
15174    #[test]
15175    fn bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations() {
15176        // The canonical per-`Caixa` `:bibliotecas` universal-axis
15177        // library-source-path-list slice pin: [`Caixa::bibliotecas`]
15178        // must return the `:bibliotecas` typed [`Vec<String>`] list
15179        // verbatim as a `&[String]`, byte-equal to the raw
15180        // `self.bibliotecas.as_slice()` access across every
15181        // representative value in the accept-set — `[]` (the "no
15182        // libraries declared" arm every `:kind` other than `Biblioteca`
15183        // + every `Biblioteca` relying on the canonical
15184        // `lib/<nome>.lisp` implicit-default path carries; the
15185        // layout's [`crate::LayoutInvariants`] `MissingLib` arm-gate
15186        // fires exactly on this empty-slot + `Biblioteca`-kind
15187        // combination), `[""]` (a past-the-guard sentinel that pins
15188        // the accessor doesn't perform a silent `[""] → []` collapse
15189        // on the empty-entry arm — validate rejects `[""]` through
15190        // `CodePathEmpty { slot: ":bibliotecas" }` but the accessor
15191        // must ship the raw slot verbatim so a validate-time gate
15192        // regression surfaces at the `feira build` phase-1 parse
15193        // boundary rather than being silently absorbed into a
15194        // library-drop), `["lib/demo.lisp"]` (the canonical single-
15195        // entry form `Caixa::template` scaffolds and every `feira init`
15196        // template emits), `["lib/demo.lisp", "lib/helpers.lisp"]`
15197        // (the canonical multi-library form the
15198        // `validate_code_paths_accepts_explicit_relative_paths_on_
15199        // every_slot` fixture emits), and `["lib/foo.lisp",
15200        // "lib/foo.lisp"]` (a past-the-guard duplicate sentinel —
15201        // validate rejects through `CodePathDuplicate { slot:
15202        // ":bibliotecas" }` per the per-slot set-not-multiset gate,
15203        // but the accessor must ship the raw slot verbatim so the
15204        // `feira build` `for entry in caixa.bibliotecas()` parse walk
15205        // sees the duplicate at the accessor boundary and struct-
15206        // literal `Caixa { bibliotecas: vec!["lib/foo.lisp".into(),
15207        // "lib/foo.lisp".into()], .. }` fixtures continue to expose
15208        // the duplicate at the accessor).
15209        //
15210        // Third outer top-level [`Caixa`] `&[T]`-return slice accessor
15211        // pin on the substrate primitive — folds on the "outer
15212        // [`Caixa`] `&[T]` slice" projection pattern
15213        // `autores_returns_autores_slice_verbatim_across_permutations`
15214        // (b5d813f) opened and
15215        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15216        // (78c7d3c) folded on, sibling in shape and idiom. Pins
15217        // against a future silent detour that returned an owned
15218        // `Vec<String>` (which would type-check but silently clone on
15219        // every accessor call, breaking the zero-cost projection
15220        // every peer sibling slice accessor carries), a `[""] → []`
15221        // collapse (which would silently absorb the `CodePathEmpty`
15222        // refusal case at the accessor boundary), or a `["lib/foo.lisp",
15223        // "lib/foo.lisp"] → ["lib/foo.lisp"]` dedup collapse (which
15224        // would silently absorb the `CodePathDuplicate` refusal case
15225        // at the accessor boundary — the per-slot set-not-multiset
15226        // gate is downstream of the accessor and must not be silently
15227        // promoted into it).
15228        for bibliotecas in [
15229            vec![],
15230            vec![""],
15231            vec!["lib/demo.lisp"],
15232            vec!["lib/demo.lisp", "lib/helpers.lisp"],
15233            vec!["lib/foo.lisp", "lib/foo.lisp"],
15234        ] {
15235            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
15236            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
15237            assert_eq!(
15238                c.bibliotecas(),
15239                expected.as_slice(),
15240                "Caixa::bibliotecas must return :bibliotecas verbatim \
15241                 (got {:?}, expected {expected:?})",
15242                c.bibliotecas(),
15243            );
15244            assert_eq!(
15245                c.bibliotecas(),
15246                c.bibliotecas.as_slice(),
15247                "Caixa::bibliotecas must byte-equal the raw \
15248                 `self.bibliotecas.as_slice()` field access across \
15249                 every value in the Vec<String> accept-set",
15250            );
15251        }
15252    }
15253
15254    #[test]
15255    fn validate_code_paths_bibliotecas_empty_arm_routes_through_accessor() {
15256        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15257        // empty-arm gate on the `:bibliotecas` slot must key off
15258        // [`Caixa::bibliotecas`], not a divergent raw
15259        // `&self.bibliotecas` field-borrow walk. Structurally: a
15260        // `Caixa { bibliotecas: vec!["".into()], .. }` must surface
15261        // the `CodePathEmpty { slot: ":bibliotecas" }` refusal
15262        // exactly, and a `Caixa { bibliotecas: vec!["lib/demo.lisp".
15263        // into()], .. }` (the canonical single-library form
15264        // `Caixa::template` scaffolds) must pass validate. The pair
15265        // jointly pins the accessor + validate-gate composition: any
15266        // future silent detour that had the accessor return an empty
15267        // slice on the `[""]` arm (a `.iter().filter(|s|
15268        // !s.is_empty()).collect()` collapse) would silently absorb
15269        // the `CodePathEmpty` refusal at the accessor boundary and
15270        // the validate gate would accept a struct-literal
15271        // `Caixa { bibliotecas: vec!["".into()], .. }` — the
15272        // composition pin catches that at caixa-core build time.
15273        //
15274        // Peer of the per-`Caixa` `validate_autores_empty_arm_routes_
15275        // through_accessor` (b5d813f) and
15276        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15277        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15278        // composition axes — same "the validate / shape-gate
15279        // predicate must route through the substrate-primitive typed
15280        // dispatch" discipline extended onto the sibling outer top-
15281        // level [`Caixa`] `&[T]`-composition surface. Nominally the
15282        // in-tree `validate_code_paths` production body still keys
15283        // off the internal `[(":bibliotecas", &self.bibliotecas,
15284        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15285        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15286        // (the tuple's homogeneous slice-typed shape blocks a per-
15287        // element accessor swap in isolation — a future companion
15288        // lift for `:exe` and `:servicos` on the same outer-`Caixa`
15289        // `&[T]` slice-accessor axis closes that tuple onto the
15290        // triple of typed dispatches as a unit); the composition pin
15291        // catches any future accessor-side silent filter drop against
15292        // that eventual tuple-closure regardless of whether the
15293        // `:bibliotecas` slot is threaded through the accessor or the
15294        // raw field access at the tuple's construction site.
15295        let c = caixa_with_code_paths(vec![""], vec![], vec![]);
15296        assert!(
15297            matches!(
15298                c.validate_code_paths(),
15299                Err(ManifestError::CodePathEmpty {
15300                    slot: ":bibliotecas"
15301                })
15302            ),
15303            "validate_code_paths must reject bibliotecas == vec![\"\"] \
15304             with CodePathEmpty {{ slot: \":bibliotecas\" }} — the \
15305             accessor and the validate gate must route through the \
15306             same substrate-primitive typed dispatch on the \
15307             :bibliotecas per-entry empty arm",
15308        );
15309        let c = caixa_with_code_paths(vec!["lib/demo.lisp"], vec![], vec![]);
15310        assert!(
15311            c.validate_code_paths().is_ok(),
15312            "validate_code_paths must accept bibliotecas == \
15313             vec![\"lib/demo.lisp\"] (the canonical single-library \
15314             shape every `feira init` template scaffolds)",
15315        );
15316    }
15317
15318    #[test]
15319    fn bibliotecas_projects_slice_by_borrow() {
15320        // The by-borrow pin: [`Caixa::bibliotecas`] returns
15321        // `&[String]` by borrow — the returned slice borrows the
15322        // underlying `Vec<String>` storage of the `:bibliotecas` slot
15323        // and the accessor must not clone the backing `Vec` on every
15324        // call. Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15325        // (b5d813f) and `etiquetas_projects_slice_by_borrow` (78c7d3c)
15326        // by-borrow pins on the sibling outer top-level [`Caixa`]
15327        // `&[String]`-return axes — the accessor's returned slice
15328        // must borrow from `&self` (the returned reference's lifetime
15329        // is tied to `&self`), and calling the accessor twice on the
15330        // same [`Caixa`] must yield slices that are pointer-equal
15331        // (the underlying byte-buffer is the storage `Vec`'s
15332        // allocation, not a fresh copy) as well as value-equal
15333        // (idempotent, no side effects on `&self`).
15334        //
15335        // Pins against a future silent detour that returned an owned
15336        // `Vec<String>` (which would type-check but silently clone on
15337        // every call, breaking the zero-cost projection every peer
15338        // sibling slice accessor carries), a `&Vec<String>` return
15339        // (which would leak the backing `Vec`'s grow/push/reserve
15340        // surface no downstream consumer reaches for), or a one-arm-
15341        // only accessor that returned a saturating value on some
15342        // sentinel input (breaking the pass-through invariant the
15343        // sibling slice accessors carry).
15344        for bibliotecas in [
15345            vec![],
15346            vec!["lib/demo.lisp"],
15347            vec!["lib/demo.lisp", "lib/helpers.lisp"],
15348            vec!["lib/foo.lisp", "lib/foo.lisp"],
15349        ] {
15350            let c = caixa_with_code_paths(bibliotecas.clone(), vec![], vec![]);
15351            let expected: Vec<String> = bibliotecas.iter().map(|s| (*s).to_string()).collect();
15352            let first = c.bibliotecas();
15353            let second = c.bibliotecas();
15354            assert_eq!(
15355                first, second,
15356                "Caixa::bibliotecas must be idempotent — two \
15357                 successive calls on the same &self must return the \
15358                 same &[String]",
15359            );
15360            assert_eq!(
15361                first.as_ptr(),
15362                second.as_ptr(),
15363                "Caixa::bibliotecas must borrow the underlying \
15364                 Vec<String> storage — two successive calls must \
15365                 return slices with the same backing pointer (a \
15366                 fresh Vec<String> clone would change the pointer on \
15367                 every call)",
15368            );
15369            assert_eq!(
15370                first,
15371                expected.as_slice(),
15372                "Caixa::bibliotecas must return :bibliotecas verbatim \
15373                 by borrow — got {first:?}, expected {expected:?}",
15374            );
15375        }
15376    }
15377
15378    // ── Caixa::exe — outer top-level &[T] slice accessor ──────────────
15379
15380    #[test]
15381    fn exe_returns_exe_slice_verbatim_across_permutations() {
15382        // The canonical per-`Caixa` `:exe` universal-axis
15383        // nix-built-executable-entry-path-list slice pin: [`Caixa::exe`]
15384        // must return the `:exe` typed [`Vec<String>`] list verbatim as
15385        // a `&[String]`, byte-equal to the raw `self.exe.as_slice()`
15386        // access across every representative value in the accept-set —
15387        // `[]` (the "no executable declared" arm every `:kind` other
15388        // than `Binario` carries; the layout's [`crate::LayoutInvariants`]
15389        // `BinarioWithoutExe` arm-gate fires exactly on this empty-slot
15390        // + `Binario`-kind combination), `[""]` (a past-the-guard
15391        // sentinel that pins the accessor doesn't perform a silent
15392        // `[""] → []` collapse on the empty-entry arm — validate rejects
15393        // `[""]` through `CodePathEmpty { slot: ":exe" }` but the
15394        // accessor must ship the raw slot verbatim so a validate-time
15395        // gate regression surfaces at the layout / `feira nix` boundary
15396        // rather than being silently absorbed into an executable-drop),
15397        // `["exe/cli"]` (the canonical single-entry Binario form every
15398        // in-tree `caixa_with_code_paths` positive control uses),
15399        // `["exe/cli", "exe/serve"]` (the canonical multi-executable
15400        // form the `validate_code_paths_accepts_explicit_relative_paths_
15401        // on_every_slot` fixture emits), and `["exe/cli", "exe/cli"]`
15402        // (a past-the-guard duplicate sentinel — validate rejects
15403        // through `CodePathDuplicate { slot: ":exe" }` per the per-slot
15404        // set-not-multiset gate, but the accessor must ship the raw
15405        // slot verbatim so struct-literal `Caixa { exe: vec!["exe/cli".
15406        // into(), "exe/cli".into()], .. }` fixtures continue to expose
15407        // the duplicate at the accessor).
15408        //
15409        // Fourth outer top-level [`Caixa`] `&[T]`-return slice accessor
15410        // pin on the substrate primitive — folds on the "outer
15411        // [`Caixa`] `&[T]` slice" projection pattern
15412        // `autores_returns_autores_slice_verbatim_across_permutations`
15413        // (b5d813f) opened,
15414        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15415        // (78c7d3c) folded on, and
15416        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15417        // (8a36c23) closed the universal-axis text-tag family of.
15418        // Opens the outer-`Caixa` foreign-code-slot `&[T]` sub-family
15419        // the sibling `:servicos` future lift closes onto. Pins against
15420        // a future silent detour that returned an owned `Vec<String>`
15421        // (which would type-check but silently clone on every accessor
15422        // call, breaking the zero-cost projection every peer sibling
15423        // slice accessor carries), a `[""] → []` collapse (which would
15424        // silently absorb the `CodePathEmpty` refusal case at the
15425        // accessor boundary), or an `["exe/cli", "exe/cli"] →
15426        // ["exe/cli"]` dedup collapse (which would silently absorb the
15427        // `CodePathDuplicate` refusal case at the accessor boundary —
15428        // the per-slot set-not-multiset gate is downstream of the
15429        // accessor and must not be silently promoted into it).
15430        for exe in [
15431            vec![],
15432            vec![""],
15433            vec!["exe/cli"],
15434            vec!["exe/cli", "exe/serve"],
15435            vec!["exe/cli", "exe/cli"],
15436        ] {
15437            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
15438            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
15439            assert_eq!(
15440                c.exe(),
15441                expected.as_slice(),
15442                "Caixa::exe must return :exe verbatim (got {:?}, \
15443                 expected {expected:?})",
15444                c.exe(),
15445            );
15446            assert_eq!(
15447                c.exe(),
15448                c.exe.as_slice(),
15449                "Caixa::exe must byte-equal the raw \
15450                 `self.exe.as_slice()` field access across every value \
15451                 in the Vec<String> accept-set",
15452            );
15453        }
15454    }
15455
15456    #[test]
15457    fn validate_code_paths_exe_empty_arm_routes_through_accessor() {
15458        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15459        // empty-arm gate on the `:exe` slot must key off
15460        // [`Caixa::exe`], not a divergent raw `&self.exe` field-borrow
15461        // walk. Structurally: a `Caixa { exe: vec!["".into()], .. }`
15462        // must surface the `CodePathEmpty { slot: ":exe" }` refusal
15463        // exactly, and a `Caixa { exe: vec!["exe/cli".into()], .. }`
15464        // (the canonical single-executable form every in-tree
15465        // `caixa_with_code_paths` positive control uses) must pass
15466        // validate. The pair jointly pins the accessor + validate-gate
15467        // composition: any future silent detour that had the accessor
15468        // return an empty slice on the `[""]` arm (a
15469        // `.iter().filter(|s| !s.is_empty()).collect()` collapse) would
15470        // silently absorb the `CodePathEmpty` refusal at the accessor
15471        // boundary and the validate gate would accept a struct-literal
15472        // `Caixa { exe: vec!["".into()], .. }` — the composition pin
15473        // catches that at caixa-core build time.
15474        //
15475        // Peer of the per-`Caixa`
15476        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15477        // (8a36c23), `validate_autores_empty_arm_routes_through_accessor`
15478        // (b5d813f), and
15479        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15480        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15481        // composition axes — same "the validate / shape-gate predicate
15482        // must route through the substrate-primitive typed dispatch"
15483        // discipline extended onto the sibling outer top-level [`Caixa`]
15484        // `&[T]`-composition surface. Nominally the in-tree
15485        // `validate_code_paths` production body still keys off the
15486        // internal `[(":bibliotecas", &self.bibliotecas,
15487        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15488        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15489        // (the tuple's homogeneous slice-typed shape blocks a per-
15490        // element accessor swap in isolation — a future companion lift
15491        // for `:servicos` on the same outer-`Caixa` `&[T]` slice-
15492        // accessor axis closes that tuple onto the triple of typed
15493        // dispatches as a unit); the composition pin catches any future
15494        // accessor-side silent filter drop against that eventual tuple-
15495        // closure regardless of whether the `:exe` slot is threaded
15496        // through the accessor or the raw field access at the tuple's
15497        // construction site.
15498        let c = caixa_with_code_paths(vec![], vec![""], vec![]);
15499        assert!(
15500            matches!(
15501                c.validate_code_paths(),
15502                Err(ManifestError::CodePathEmpty { slot: ":exe" })
15503            ),
15504            "validate_code_paths must reject exe == vec![\"\"] \
15505             with CodePathEmpty {{ slot: \":exe\" }} — the \
15506             accessor and the validate gate must route through the \
15507             same substrate-primitive typed dispatch on the \
15508             :exe per-entry empty arm",
15509        );
15510        let c = caixa_with_code_paths(vec![], vec!["exe/cli"], vec![]);
15511        assert!(
15512            c.validate_code_paths().is_ok(),
15513            "validate_code_paths must accept exe == vec![\"exe/cli\"] \
15514             (the canonical single-executable shape every in-tree \
15515             `caixa_with_code_paths` positive control uses)",
15516        );
15517    }
15518
15519    #[test]
15520    fn exe_projects_slice_by_borrow() {
15521        // The by-borrow pin: [`Caixa::exe`] returns `&[String]` by
15522        // borrow — the returned slice borrows the underlying
15523        // `Vec<String>` storage of the `:exe` slot and the accessor
15524        // must not clone the backing `Vec` on every call. Peer of the
15525        // per-`Caixa` `autores_projects_slice_by_borrow` (b5d813f),
15526        // `etiquetas_projects_slice_by_borrow` (78c7d3c), and
15527        // `bibliotecas_projects_slice_by_borrow` (8a36c23) by-borrow
15528        // pins on the sibling outer top-level [`Caixa`] `&[String]`-
15529        // return axes — the accessor's returned slice must borrow from
15530        // `&self` (the returned reference's lifetime is tied to
15531        // `&self`), and calling the accessor twice on the same
15532        // [`Caixa`] must yield slices that are pointer-equal (the
15533        // underlying byte-buffer is the storage `Vec`'s allocation,
15534        // not a fresh copy) as well as value-equal (idempotent, no
15535        // side effects on `&self`).
15536        //
15537        // Pins against a future silent detour that returned an owned
15538        // `Vec<String>` (which would type-check but silently clone on
15539        // every call, breaking the zero-cost projection every peer
15540        // sibling slice accessor carries), a `&Vec<String>` return
15541        // (which would leak the backing `Vec`'s grow/push/reserve
15542        // surface no downstream consumer reaches for), or a one-arm-
15543        // only accessor that returned a saturating value on some
15544        // sentinel input (breaking the pass-through invariant the
15545        // sibling slice accessors carry).
15546        for exe in [
15547            vec![],
15548            vec!["exe/cli"],
15549            vec!["exe/cli", "exe/serve"],
15550            vec!["exe/cli", "exe/cli"],
15551        ] {
15552            let c = caixa_with_code_paths(vec![], exe.clone(), vec![]);
15553            let expected: Vec<String> = exe.iter().map(|s| (*s).to_string()).collect();
15554            let first = c.exe();
15555            let second = c.exe();
15556            assert_eq!(
15557                first, second,
15558                "Caixa::exe must be idempotent — two successive calls \
15559                 on the same &self must return the same &[String]",
15560            );
15561            assert_eq!(
15562                first.as_ptr(),
15563                second.as_ptr(),
15564                "Caixa::exe must borrow the underlying Vec<String> \
15565                 storage — two successive calls must return slices \
15566                 with the same backing pointer (a fresh Vec<String> \
15567                 clone would change the pointer on every call)",
15568            );
15569            assert_eq!(
15570                first,
15571                expected.as_slice(),
15572                "Caixa::exe must return :exe verbatim by borrow — \
15573                 got {first:?}, expected {expected:?}",
15574            );
15575        }
15576    }
15577
15578    // ── Caixa::servicos — outer top-level &[T] slice accessor ─────────
15579
15580    #[test]
15581    fn servicos_returns_servicos_slice_verbatim_across_permutations() {
15582        // The canonical per-`Caixa` `:servicos` universal-axis
15583        // ComputeUnit-CR-YAML-entry-path-list slice pin:
15584        // [`Caixa::servicos`] must return the `:servicos` typed
15585        // [`Vec<String>`] list verbatim as a `&[String]`, byte-equal to
15586        // the raw `self.servicos.as_slice()` access across every
15587        // representative value in the accept-set — `[]` (the "no
15588        // ComputeUnit-CR declared" arm every `:kind` other than
15589        // `Servico` carries; the layout's [`crate::LayoutInvariants`]
15590        // `ServicoWithoutServicos` arm-gate fires exactly on this
15591        // empty-slot + `Servico`-kind combination), `[""]` (a past-the-
15592        // guard sentinel that pins the accessor doesn't perform a
15593        // silent `[""] → []` collapse on the empty-entry arm — validate
15594        // rejects `[""]` through `CodePathEmpty { slot: ":servicos" }`
15595        // but the accessor must ship the raw slot verbatim so a
15596        // validate-time gate regression surfaces at the layout /
15597        // per-Servico renderer boundary rather than being silently
15598        // absorbed into a component-drop),
15599        // `["servicos/demo.computeunit.yaml"]` (the canonical
15600        // singleton V0-shape every in-tree `caixa_with_code_paths`
15601        // positive control uses; the same shape
15602        // [`crate::require_single_servico`] admits),
15603        // `["servicos/a.computeunit.yaml", "servicos/b.computeunit.
15604        // yaml"]` (a past-the-guard `len != 1` sentinel — the V0
15605        // singularity gate rejects through `ServicoCountMismatch
15606        // { count: 2 }` but the accessor must ship the raw slot
15607        // verbatim so struct-literal `Caixa { servicos: vec![...,
15608        // ...], .. }` fixtures continue to expose the count at the
15609        // accessor), and `["servicos/a.computeunit.yaml",
15610        // "servicos/a.computeunit.yaml"]` (a past-the-guard duplicate
15611        // sentinel — validate rejects through
15612        // `CodePathDuplicate { slot: ":servicos" }` per the per-slot
15613        // set-not-multiset gate, but the accessor must ship the raw
15614        // slot verbatim so struct-literal fixtures continue to expose
15615        // the duplicate at the accessor).
15616        //
15617        // Fifth and final outer top-level [`Caixa`] `&[T]`-return
15618        // slice accessor pin on the substrate primitive — folds on the
15619        // "outer [`Caixa`] `&[T]` slice" projection pattern
15620        // `autores_returns_autores_slice_verbatim_across_permutations`
15621        // (b5d813f) opened,
15622        // `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15623        // (78c7d3c) folded on,
15624        // `bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15625        // (8a36c23) closed the universal-axis text-tag family of, and
15626        // `exe_returns_exe_slice_verbatim_across_permutations`
15627        // (65d9527) opened the foreign-code-slot sub-family of. Closes
15628        // the outer-`Caixa` foreign-code-slot `&[T]` sub-family — the
15629        // trio of code-surface list slots (`:bibliotecas` + `:exe` +
15630        // `:servicos`) now each carries a substrate-canonical slice
15631        // accessor. Pins against a future silent detour that returned
15632        // an owned `Vec<String>` (which would type-check but silently
15633        // clone on every accessor call, breaking the zero-cost
15634        // projection every peer sibling slice accessor carries), a
15635        // `[""] → []` collapse (which would silently absorb the
15636        // `CodePathEmpty` refusal case at the accessor boundary), an
15637        // `[a, a] → [a]` dedup collapse (which would silently absorb
15638        // the `CodePathDuplicate` refusal case at the accessor
15639        // boundary — the per-slot set-not-multiset gate is downstream
15640        // of the accessor and must not be silently promoted into it),
15641        // or a `[a, b] → [a]` singleton collapse (which would silently
15642        // absorb the V0 `ServicoCountMismatch` refusal case at the
15643        // accessor boundary — the V0 singularity gate is downstream of
15644        // the accessor and must not be silently promoted into it).
15645        for servicos in [
15646            vec![],
15647            vec![""],
15648            vec!["servicos/demo.computeunit.yaml"],
15649            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
15650            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
15651        ] {
15652            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
15653            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
15654            assert_eq!(
15655                c.servicos(),
15656                expected.as_slice(),
15657                "Caixa::servicos must return :servicos verbatim (got \
15658                 {:?}, expected {expected:?})",
15659                c.servicos(),
15660            );
15661            assert_eq!(
15662                c.servicos(),
15663                c.servicos.as_slice(),
15664                "Caixa::servicos must byte-equal the raw \
15665                 `self.servicos.as_slice()` field access across every \
15666                 value in the Vec<String> accept-set",
15667            );
15668        }
15669    }
15670
15671    #[test]
15672    fn validate_code_paths_servicos_empty_arm_routes_through_accessor() {
15673        // Composition pin: [`Caixa::validate_code_paths`]'s per-entry
15674        // empty-arm gate on the `:servicos` slot must key off
15675        // [`Caixa::servicos`], not a divergent raw `&self.servicos`
15676        // field-borrow walk. Structurally: a `Caixa { servicos:
15677        // vec!["".into()], .. }` must surface the `CodePathEmpty
15678        // { slot: ":servicos" }` refusal exactly, and a `Caixa
15679        // { servicos: vec!["servicos/demo.computeunit.yaml".into()],
15680        // .. }` (the canonical singleton V0-shape every in-tree
15681        // `caixa_with_code_paths` positive control uses) must pass
15682        // validate. The pair jointly pins the accessor + validate-gate
15683        // composition: any future silent detour that had the accessor
15684        // return an empty slice on the `[""]` arm (a `.iter().filter
15685        // (|s| !s.is_empty()).collect()` collapse) would silently
15686        // absorb the `CodePathEmpty` refusal at the accessor boundary
15687        // and the validate gate would accept a struct-literal
15688        // `Caixa { servicos: vec!["".into()], .. }` — the composition
15689        // pin catches that at caixa-core build time.
15690        //
15691        // Peer of the per-`Caixa`
15692        // `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15693        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
15694        // (65d9527), `validate_autores_empty_arm_routes_through_accessor`
15695        // (b5d813f), and
15696        // `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15697        // (78c7d3c) accessor-composition pins on the sibling `&[T]`-
15698        // composition axes — same "the validate / shape-gate predicate
15699        // must route through the substrate-primitive typed dispatch"
15700        // discipline extended onto the sibling outer top-level
15701        // [`Caixa`] `&[T]`-composition surface, closing the trio of
15702        // code-surface accessor-composition pins on the same axis.
15703        // Nominally the in-tree `validate_code_paths` production body
15704        // still keys off the internal
15705        // `[(":bibliotecas", &self.bibliotecas,
15706        // CodePathFileType::LispSource), (":exe", &self.exe, ..),
15707        // (":servicos", &self.servicos, ..)]` per-slot dispatch tuple
15708        // (the tuple's homogeneous `&Vec<String>`-typed shape blocks a
15709        // per-element accessor swap in isolation — a future companion
15710        // lift promotes the tuple's element type to `&[String]` and
15711        // threads the triple of typed dispatches through as a unit);
15712        // the composition pin catches any future accessor-side silent
15713        // filter drop against that eventual tuple-closure regardless
15714        // of whether the `:servicos` slot is threaded through the
15715        // accessor or the raw field access at the tuple's construction
15716        // site.
15717        let c = caixa_with_code_paths(vec![], vec![], vec![""]);
15718        assert!(
15719            matches!(
15720                c.validate_code_paths(),
15721                Err(ManifestError::CodePathEmpty { slot: ":servicos" })
15722            ),
15723            "validate_code_paths must reject servicos == vec![\"\"] \
15724             with CodePathEmpty {{ slot: \":servicos\" }} — the \
15725             accessor and the validate gate must route through the \
15726             same substrate-primitive typed dispatch on the \
15727             :servicos per-entry empty arm",
15728        );
15729        let c = caixa_with_code_paths(vec![], vec![], vec!["servicos/demo.computeunit.yaml"]);
15730        assert!(
15731            c.validate_code_paths().is_ok(),
15732            "validate_code_paths must accept servicos == \
15733             vec![\"servicos/demo.computeunit.yaml\"] (the canonical \
15734             singleton V0-shape every in-tree `caixa_with_code_paths` \
15735             positive control uses)",
15736        );
15737    }
15738
15739    #[test]
15740    fn servicos_projects_slice_by_borrow() {
15741        // The by-borrow pin: [`Caixa::servicos`] returns `&[String]` by
15742        // borrow — the returned slice borrows the underlying
15743        // `Vec<String>` storage of the `:servicos` slot and the
15744        // accessor must not clone the backing `Vec` on every call.
15745        // Peer of the per-`Caixa` `autores_projects_slice_by_borrow`
15746        // (b5d813f), `etiquetas_projects_slice_by_borrow` (78c7d3c),
15747        // `bibliotecas_projects_slice_by_borrow` (8a36c23), and
15748        // `exe_projects_slice_by_borrow` (65d9527) by-borrow pins on
15749        // the sibling outer top-level [`Caixa`] `&[String]`-return
15750        // axes — the accessor's returned slice must borrow from
15751        // `&self` (the returned reference's lifetime is tied to
15752        // `&self`), and calling the accessor twice on the same
15753        // [`Caixa`] must yield slices that are pointer-equal (the
15754        // underlying byte-buffer is the storage `Vec`'s allocation,
15755        // not a fresh copy) as well as value-equal (idempotent, no
15756        // side effects on `&self`).
15757        //
15758        // Pins against a future silent detour that returned an owned
15759        // `Vec<String>` (which would type-check but silently clone on
15760        // every call, breaking the zero-cost projection every peer
15761        // sibling slice accessor carries), a `&Vec<String>` return
15762        // (which would leak the backing `Vec`'s grow/push/reserve
15763        // surface no downstream consumer reaches for), or a one-arm-
15764        // only accessor that returned a saturating value on some
15765        // sentinel input (breaking the pass-through invariant the
15766        // sibling slice accessors carry).
15767        for servicos in [
15768            vec![],
15769            vec!["servicos/demo.computeunit.yaml"],
15770            vec!["servicos/a.computeunit.yaml", "servicos/b.computeunit.yaml"],
15771            vec!["servicos/a.computeunit.yaml", "servicos/a.computeunit.yaml"],
15772        ] {
15773            let c = caixa_with_code_paths(vec![], vec![], servicos.clone());
15774            let expected: Vec<String> = servicos.iter().map(|s| (*s).to_string()).collect();
15775            let first = c.servicos();
15776            let second = c.servicos();
15777            assert_eq!(
15778                first, second,
15779                "Caixa::servicos must be idempotent — two successive \
15780                 calls on the same &self must return the same &[String]",
15781            );
15782            assert_eq!(
15783                first.as_ptr(),
15784                second.as_ptr(),
15785                "Caixa::servicos must borrow the underlying \
15786                 Vec<String> storage — two successive calls must \
15787                 return slices with the same backing pointer (a fresh \
15788                 Vec<String> clone would change the pointer on every \
15789                 call)",
15790            );
15791            assert_eq!(
15792                first,
15793                expected.as_slice(),
15794                "Caixa::servicos must return :servicos verbatim by \
15795                 borrow — got {first:?}, expected {expected:?}",
15796            );
15797        }
15798    }
15799
15800    // ── Caixa::deps — outer top-level &[Dep] slice accessor ───────────
15801
15802    fn caixa_with_deps(deps: Vec<Dep>) -> Caixa {
15803        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15804        c.deps = deps;
15805        c
15806    }
15807
15808    #[test]
15809    fn deps_returns_deps_slice_verbatim_across_permutations() {
15810        // The canonical per-`Caixa` `:deps` universal-axis runtime-
15811        // dependency-declaration-list slice pin: [`Caixa::deps`] must
15812        // return the `:deps` typed [`Vec<Dep>`] list verbatim as a
15813        // `&[Dep]`, element-equal to the raw `self.deps.as_slice()`
15814        // access across every representative value in the accept-set —
15815        // `[]` (the "no runtime deps declared" arm every existing
15816        // fixture without a `:deps` line carries; the
15817        // [`Caixa::template`] scaffold emits `:deps ()`), a canonical
15818        // single-entry list (the shape most consumer caixas carry), a
15819        // canonical two-entry list (the multi-dep runtime closure), and
15820        // two past-the-guard sentinels — a `[""]`-`:nome` entry
15821        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
15822        // `NomeInvalid` but the accessor must ship the raw slot
15823        // verbatim) and a `[a, a]` duplicate (validate rejects through
15824        // `DuplicateNome { list: ":deps" }` but the accessor must ship
15825        // the raw slot verbatim so struct-literal fixtures continue to
15826        // expose the duplicate at the accessor).
15827        //
15828        // First outer top-level [`Caixa`] `&[Dep]`-return slice accessor
15829        // pin on the substrate primitive — opens the outer-`Caixa`
15830        // dependency-slot `&[Dep]` sub-family the sibling `:deps-dev`
15831        // future lift closes on. Peer of the closed outer-`Caixa`
15832        // foreign-code-slot `&[String]` sub-family
15833        // (`bibliotecas_returns_bibliotecas_slice_verbatim_across_permutations`
15834        // 8a36c23, `exe_returns_exe_slice_verbatim_across_permutations`
15835        // 65d9527, `servicos_returns_servicos_slice_verbatim_across_permutations`
15836        // 611f78b) and the outer-`Caixa` universal-axis text-tag family
15837        // (`autores_returns_autores_slice_verbatim_across_permutations`
15838        // b5d813f, `etiquetas_returns_etiquetas_slice_verbatim_across_permutations`
15839        // 78c7d3c) — extends the "outer [`Caixa`] `&[T]` slice"
15840        // projection pattern onto a novel element-type axis (`Dep`
15841        // composite vs the prior sibling family's `String` scalar).
15842        // Pins against a future silent detour that returned an owned
15843        // `Vec<Dep>` (which would type-check but silently clone on every
15844        // accessor call, breaking the zero-cost projection every peer
15845        // sibling slice accessor carries), a `[""] → []` collapse (which
15846        // would silently absorb the `NomeEmpty` refusal case at the
15847        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
15848        // would silently absorb the `DuplicateNome` refusal case at the
15849        // accessor boundary).
15850        for deps in [
15851            vec![],
15852            vec![Dep::simple("", "^0.1")],
15853            vec![Dep::simple("caixa-teia", "^0.1")],
15854            vec![
15855                Dep::simple("caixa-teia", "^0.1"),
15856                Dep::simple("caixa-core", "^0.1"),
15857            ],
15858            vec![
15859                Dep::simple("caixa-teia", "^0.1"),
15860                Dep::simple("caixa-teia", "^0.2"),
15861            ],
15862        ] {
15863            let c = caixa_with_deps(deps.clone());
15864            assert_eq!(
15865                c.deps(),
15866                deps.as_slice(),
15867                "Caixa::deps must return :deps verbatim (got {:?}, \
15868                 expected {deps:?})",
15869                c.deps(),
15870            );
15871            assert_eq!(
15872                c.deps(),
15873                c.deps.as_slice(),
15874                "Caixa::deps must element-equal the raw \
15875                 `self.deps.as_slice()` field access across every \
15876                 value in the Vec<Dep> accept-set",
15877            );
15878        }
15879    }
15880
15881    #[test]
15882    fn validate_deps_duplicate_arm_routes_through_accessor() {
15883        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps`
15884        // duplicate-`:nome` gate must key off [`Caixa::deps`], not the
15885        // raw `&self.deps` field-borrow walk. Structurally: a `Caixa
15886        // { deps: vec![Dep::simple("d", "^0.1"), Dep::simple("d",
15887        // "^0.2")], .. }` must surface the `DuplicateNome { list:
15888        // ":deps" }` refusal exactly, and a `Caixa { deps: vec![
15889        // Dep::simple("d", "^0.1")], .. }` (the canonical single-entry
15890        // form) must pass validate. The pair jointly pins the accessor +
15891        // validate-gate composition: any future silent detour that had
15892        // the accessor return a dedupped slice on the `[a, a]` arm (a
15893        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
15894        // would silently absorb the `DuplicateNome` refusal at the
15895        // accessor boundary and the validate gate would accept a
15896        // struct-literal `Caixa` carrying the drift — the composition
15897        // pin catches that at caixa-core build time.
15898        //
15899        // Peer of the per-`Caixa`
15900        // `validate_autores_empty_entry_arm_routes_through_accessor`
15901        // (b5d813f), `validate_etiquetas_empty_entry_arm_routes_through_accessor`
15902        // (78c7d3c), `validate_code_paths_bibliotecas_empty_arm_routes_through_accessor`
15903        // (8a36c23), `validate_code_paths_exe_empty_arm_routes_through_accessor`
15904        // (65d9527), and `validate_code_paths_servicos_empty_arm_routes_through_accessor`
15905        // (611f78b) accessor-composition pins on the sibling `&[T]`-
15906        // composition axes — same "the validate gate must route through
15907        // the substrate-primitive typed dispatch" discipline extended
15908        // onto the sibling outer top-level [`Caixa`] `&[Dep]`-
15909        // composition surface, opening the outer-`Caixa` dependency-slot
15910        // arm of the composition-pin family.
15911        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
15912        let err = c.validate_deps().unwrap_err();
15913        assert!(
15914            matches!(
15915                err,
15916                DepError::DuplicateNome { ref nome, list } if nome == "d"
15917                    && list == crate::render::DEP_AUTHOR_KEY_DEPS
15918            ),
15919            "validate_deps must reject deps == \
15920             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
15921             DuplicateNome {{ nome: \"d\", list: \":deps\" }} — the \
15922             accessor and the validate gate must route through the \
15923             same substrate-primitive typed dispatch on the :deps \
15924             within-list duplicate arm (got {err:?})",
15925        );
15926        let c = caixa_with_deps(vec![Dep::simple("d", "^0.1")]);
15927        assert!(
15928            c.validate_deps().is_ok(),
15929            "validate_deps must accept deps == vec![Dep(\"d\",\"^0.1\")] \
15930             (the canonical single-entry form)",
15931        );
15932    }
15933
15934    #[test]
15935    fn deps_projects_slice_by_borrow() {
15936        // The by-borrow pin: [`Caixa::deps`] returns `&[Dep]` by borrow
15937        // — the returned slice borrows the underlying `Vec<Dep>` storage
15938        // of the `:deps` slot and the accessor must not clone the
15939        // backing `Vec` on every call. Peer of the per-`Caixa`
15940        // `autores_projects_slice_by_borrow` (b5d813f),
15941        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
15942        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
15943        // `exe_projects_slice_by_borrow` (65d9527), and
15944        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
15945        // on the sibling outer top-level [`Caixa`] `&[String]`-return
15946        // axes — the accessor's returned slice must borrow from `&self`
15947        // (the returned reference's lifetime is tied to `&self`), and
15948        // calling the accessor twice on the same [`Caixa`] must yield
15949        // slices that are pointer-equal (the underlying byte-buffer is
15950        // the storage `Vec`'s allocation, not a fresh copy) as well as
15951        // value-equal (idempotent, no side effects on `&self`).
15952        //
15953        // Pins against a future silent detour that returned an owned
15954        // `Vec<Dep>` (which would type-check but silently clone on
15955        // every call), a `&Vec<Dep>` return (which would leak the
15956        // backing `Vec`'s grow/push/reserve surface no downstream
15957        // consumer reaches for), or a one-arm-only accessor that
15958        // returned a saturating value on some sentinel input.
15959        for deps in [
15960            vec![],
15961            vec![Dep::simple("caixa-teia", "^0.1")],
15962            vec![
15963                Dep::simple("caixa-teia", "^0.1"),
15964                Dep::simple("caixa-core", "^0.1"),
15965            ],
15966        ] {
15967            let c = caixa_with_deps(deps.clone());
15968            let first = c.deps();
15969            let second = c.deps();
15970            assert_eq!(
15971                first, second,
15972                "Caixa::deps must be idempotent — two successive calls \
15973                 on the same &self must return the same &[Dep]",
15974            );
15975            assert_eq!(
15976                first.as_ptr(),
15977                second.as_ptr(),
15978                "Caixa::deps must borrow the underlying Vec<Dep> \
15979                 storage — two successive calls must return slices \
15980                 with the same backing pointer (a fresh Vec<Dep> clone \
15981                 would change the pointer on every call)",
15982            );
15983            assert_eq!(
15984                first,
15985                deps.as_slice(),
15986                "Caixa::deps must return :deps verbatim by borrow — \
15987                 got {first:?}, expected {deps:?}",
15988            );
15989        }
15990    }
15991
15992    // ── Caixa::deps_dev — outer top-level &[Dep] slice accessor ──────
15993
15994    fn caixa_with_deps_dev(deps_dev: Vec<Dep>) -> Caixa {
15995        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
15996        c.deps_dev = deps_dev;
15997        c
15998    }
15999
16000    #[test]
16001    fn deps_dev_returns_deps_dev_slice_verbatim_across_permutations() {
16002        // The canonical per-`Caixa` `:deps-dev` universal-axis dev-only-
16003        // dependency-declaration-list slice pin: [`Caixa::deps_dev`]
16004        // must return the `:deps-dev` typed [`Vec<Dep>`] list verbatim as
16005        // a `&[Dep]`, element-equal to the raw `self.deps_dev.as_slice()`
16006        // access across every representative value in the accept-set —
16007        // `[]` (the "no dev deps declared" arm every existing fixture
16008        // without a `:deps-dev` line carries; the [`Caixa::template`]
16009        // scaffold emits `:deps-dev ()`), a canonical single-entry list
16010        // (the shape most consumer caixas carry — a `tatara-check` dev
16011        // pin), a canonical two-entry list (the multi-dev-dep closure),
16012        // and two past-the-guard sentinels — a `[""]`-`:nome` entry
16013        // ([`Self::validate_deps`] rejects through `NomeEmpty` /
16014        // `NomeInvalid` but the accessor must ship the raw slot
16015        // verbatim) and a `[a, a]` duplicate (validate rejects through
16016        // `DuplicateNome { list: ":deps-dev" }` but the accessor must
16017        // ship the raw slot verbatim so struct-literal fixtures continue
16018        // to expose the duplicate at the accessor).
16019        //
16020        // Second outer top-level [`Caixa`] `&[Dep]`-return slice-accessor
16021        // pin on the substrate primitive — closes the outer-`Caixa`
16022        // dependency-slot `&[Dep]` sub-family the sibling
16023        // `deps_returns_deps_slice_verbatim_across_permutations`
16024        // (ad34b4e) opened on. Folds the "outer [`Caixa`] `&[Dep]`
16025        // slice" projection pattern onto the sibling dev-dep axis —
16026        // pins against a future silent detour that returned an owned
16027        // `Vec<Dep>` (which would type-check but silently clone on every
16028        // accessor call, breaking the zero-cost projection every peer
16029        // sibling slice accessor carries), a `[""] → []` collapse (which
16030        // would silently absorb the `NomeEmpty` refusal case at the
16031        // accessor boundary), or a `[a, a] → [a]` dedup collapse (which
16032        // would silently absorb the `DuplicateNome` refusal case at the
16033        // accessor boundary).
16034        for deps_dev in [
16035            vec![],
16036            vec![Dep::simple("", "^0.1")],
16037            vec![Dep::simple("tatara-check", "^0.1")],
16038            vec![
16039                Dep::simple("tatara-check", "^0.1"),
16040                Dep::simple("caixa-lint", "^0.1"),
16041            ],
16042            vec![
16043                Dep::simple("tatara-check", "^0.1"),
16044                Dep::simple("tatara-check", "^0.2"),
16045            ],
16046        ] {
16047            let c = caixa_with_deps_dev(deps_dev.clone());
16048            assert_eq!(
16049                c.deps_dev(),
16050                deps_dev.as_slice(),
16051                "Caixa::deps_dev must return :deps-dev verbatim (got \
16052                 {:?}, expected {deps_dev:?})",
16053                c.deps_dev(),
16054            );
16055            assert_eq!(
16056                c.deps_dev(),
16057                c.deps_dev.as_slice(),
16058                "Caixa::deps_dev must element-equal the raw \
16059                 `self.deps_dev.as_slice()` field access across every \
16060                 value in the Vec<Dep> accept-set",
16061            );
16062        }
16063    }
16064
16065    #[test]
16066    fn validate_deps_duplicate_deps_dev_arm_routes_through_accessor() {
16067        // Composition pin: [`Caixa::validate_deps`]'s within-`:deps-dev`
16068        // duplicate-`:nome` gate must key off [`Caixa::deps_dev`], not
16069        // the raw `&self.deps_dev` field-borrow walk. Structurally: a
16070        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1"),
16071        // Dep::simple("d", "^0.2")], .. }` must surface the
16072        // `DuplicateNome { list: ":deps-dev" }` refusal exactly, and a
16073        // `Caixa { deps_dev: vec![Dep::simple("d", "^0.1")], .. }` (the
16074        // canonical single-entry form) must pass validate. The pair
16075        // jointly pins the accessor + validate-gate composition: any
16076        // future silent detour that had the accessor return a dedupped
16077        // slice on the `[a, a]` arm (a
16078        // `.iter().unique_by(|d| d.nome.as_str()).collect()` collapse)
16079        // would silently absorb the `DuplicateNome` refusal at the
16080        // accessor boundary and the validate gate would accept a
16081        // struct-literal `Caixa` carrying the drift — the composition
16082        // pin catches that at caixa-core build time.
16083        //
16084        // Peer of `validate_deps_duplicate_arm_routes_through_accessor`
16085        // (ad34b4e) on the sibling `:deps` axis — same "the validate
16086        // gate must route through the substrate-primitive typed
16087        // dispatch" discipline folded onto the sibling `:deps-dev`
16088        // axis, closing the two-list dep-graph composition-pin family.
16089        // The `:deps-dev` diagnostic must carry the
16090        // `DEP_AUTHOR_KEY_DEPS_DEV` list-tag (not
16091        // `DEP_AUTHOR_KEY_DEPS`) so the emitted error names the
16092        // offending list unambiguously.
16093        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1"), Dep::simple("d", "^0.2")]);
16094        let err = c.validate_deps().unwrap_err();
16095        assert!(
16096            matches!(
16097                err,
16098                DepError::DuplicateNome { ref nome, list } if nome == "d"
16099                    && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
16100            ),
16101            "validate_deps must reject deps_dev == \
16102             vec![Dep(\"d\",\"^0.1\"), Dep(\"d\",\"^0.2\")] with \
16103             DuplicateNome {{ nome: \"d\", list: \":deps-dev\" }} — the \
16104             accessor and the validate gate must route through the \
16105             same substrate-primitive typed dispatch on the :deps-dev \
16106             within-list duplicate arm (got {err:?})",
16107        );
16108        let c = caixa_with_deps_dev(vec![Dep::simple("d", "^0.1")]);
16109        assert!(
16110            c.validate_deps().is_ok(),
16111            "validate_deps must accept deps_dev == \
16112             vec![Dep(\"d\",\"^0.1\")] (the canonical single-entry form)",
16113        );
16114    }
16115
16116    #[test]
16117    fn deps_dev_projects_slice_by_borrow() {
16118        // The by-borrow pin: [`Caixa::deps_dev`] returns `&[Dep]` by
16119        // borrow — the returned slice borrows the underlying `Vec<Dep>`
16120        // storage of the `:deps-dev` slot and the accessor must not
16121        // clone the backing `Vec` on every call. Peer of
16122        // `deps_projects_slice_by_borrow` (ad34b4e) on the sibling
16123        // `:deps` axis, and of the per-`Caixa`
16124        // `autores_projects_slice_by_borrow` (b5d813f),
16125        // `etiquetas_projects_slice_by_borrow` (78c7d3c),
16126        // `bibliotecas_projects_slice_by_borrow` (8a36c23),
16127        // `exe_projects_slice_by_borrow` (65d9527), and
16128        // `servicos_projects_slice_by_borrow` (611f78b) by-borrow pins
16129        // on the sibling outer top-level [`Caixa`] `&[String]`-return
16130        // axes — the accessor's returned slice must borrow from `&self`
16131        // (the returned reference's lifetime is tied to `&self`), and
16132        // calling the accessor twice on the same [`Caixa`] must yield
16133        // slices that are pointer-equal (the underlying byte-buffer is
16134        // the storage `Vec`'s allocation, not a fresh copy) as well as
16135        // value-equal (idempotent, no side effects on `&self`).
16136        //
16137        // Pins against a future silent detour that returned an owned
16138        // `Vec<Dep>` (which would type-check but silently clone on
16139        // every call), a `&Vec<Dep>` return (which would leak the
16140        // backing `Vec`'s grow/push/reserve surface no downstream
16141        // consumer reaches for), or a one-arm-only accessor that
16142        // returned a saturating value on some sentinel input.
16143        for deps_dev in [
16144            vec![],
16145            vec![Dep::simple("tatara-check", "^0.1")],
16146            vec![
16147                Dep::simple("tatara-check", "^0.1"),
16148                Dep::simple("caixa-lint", "^0.1"),
16149            ],
16150        ] {
16151            let c = caixa_with_deps_dev(deps_dev.clone());
16152            let first = c.deps_dev();
16153            let second = c.deps_dev();
16154            assert_eq!(
16155                first, second,
16156                "Caixa::deps_dev must be idempotent — two successive \
16157                 calls on the same &self must return the same &[Dep]",
16158            );
16159            assert_eq!(
16160                first.as_ptr(),
16161                second.as_ptr(),
16162                "Caixa::deps_dev must borrow the underlying Vec<Dep> \
16163                 storage — two successive calls must return slices \
16164                 with the same backing pointer (a fresh Vec<Dep> clone \
16165                 would change the pointer on every call)",
16166            );
16167            assert_eq!(
16168                first,
16169                deps_dev.as_slice(),
16170                "Caixa::deps_dev must return :deps-dev verbatim by \
16171                 borrow — got {first:?}, expected {deps_dev:?}",
16172            );
16173        }
16174    }
16175
16176    // ── Caixa::limits — outer top-level Option<&LimitsSpec> composite-reference accessor ──
16177
16178    fn caixa_with_limits(limits: Option<crate::LimitsSpec>) -> Caixa {
16179        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16180        c.limits = limits;
16181        c
16182    }
16183
16184    #[test]
16185    fn limits_returns_limits_option_ref_verbatim_across_permutations() {
16186        // The canonical per-`Caixa` `:limits` M2 typed-slot outer-
16187        // composite optional-composite-reference-shape pin:
16188        // [`Caixa::limits`] must return the `:limits` typed
16189        // `Option<LimitsSpec>` verbatim as an `Option<&LimitsSpec>`
16190        // reference over the same backing storage the raw
16191        // `self.limits.as_ref()` field access borrows from, byte-equal
16192        // across every representative fixture in the accept-set — the
16193        // author-omitted `None` shape (the "engine-default applies"
16194        // partition every downstream Servico M2 overlay emitter treats
16195        // as "emit nothing"), the empty-composite `Some(LimitsSpec {
16196        // .. default })` shape ([`LimitsSpec::is_empty`] holds — every
16197        // per-axis cap is `None`, so the peer M2 overlay emitter's
16198        // `.is_empty()`-gated projection still emits nothing but the
16199        // outer presence-bit is `Some`, so [`Caixa::declared_servico_slots`]
16200        // still pushes the `M2_AUTHOR_KEY_LIMITS` label), a single-axis
16201        // fixture (only `:memory` set — the canonical shape most
16202        // memory-heavy Servicos carry), and a fully-populated composite
16203        // (every per-axis cap set — the canonical shape a
16204        // sandboxed-by-default Servico carries).
16205        //
16206        // Pins against a future silent detour that returned a fresh-
16207        // cloned [`LimitsSpec`] copy (which would type-check via the
16208        // `Clone` impl but silently break every downstream caller that
16209        // relied on the reference sharing the composite's backing
16210        // identity), a reference to an operator-resolved overlay (the
16211        // future per-cluster `:limits-overrides` slot — its resolution
16212        // must land at exactly this accessor body, not silently divert
16213        // the raw slot away from a second consumer), a
16214        // `None` → `Some(LimitsSpec::default)` cluster-default
16215        // projection (which would collapse the load-bearing
16216        // "author-omitted `:limits` ⇒ engine-default applies" partition
16217        // the peer [`crate::render::servico_m2_overlay`] emitter and
16218        // the peer [`Caixa::declared_servico_slots`] enumerator both
16219        // read), or an axis-shuffled projection (a future detour that
16220        // swapped `memory` and `fuel` through the accessor would
16221        // silently split the paired [`crate::StandardLayout::verify`]
16222        // per-`:limits` shape gate's traversal input from the peer
16223        // `servico_m2_overlay` emitter's projection input).
16224        //
16225        // First outer top-level [`Caixa`] `Option<&Composite>`-return
16226        // composite-reference accessor pin on the substrate primitive
16227        // — opens the outer-`Caixa` `Option<&Composite>` composite-
16228        // reference projection pattern the sibling `:behavior`
16229        // [`crate::BehaviorSpec`] / `:politicas`
16230        // [`crate::aplicacao::MeshPolicy`] / `:placement`
16231        // [`crate::aplicacao::Placement`] / `:entrada`
16232        // [`crate::aplicacao::Entrada`] future outer-composite lifts
16233        // fold on. Peer of the closed M3 outer-composite family the
16234        // sibling [`crate::AplicacaoSpec::politicas`] (534dc21) /
16235        // [`crate::AplicacaoSpec::placement`] (9abb8f0) /
16236        // [`crate::AplicacaoSpec::entrada`] (d32111c) composite-
16237        // reference accessor pins already carry on the outer
16238        // [`crate::AplicacaoSpec`] altitude — extends the outer-
16239        // accessor byte-equal-projection discipline onto the outer
16240        // top-level [`Caixa`] M2 Servico-runtime slot altitude.
16241        use crate::LimitsSpec;
16242        use std::time::Duration;
16243        let fixtures: Vec<Option<LimitsSpec>> = vec![
16244            None,
16245            Some(LimitsSpec::default()),
16246            Some(LimitsSpec {
16247                memory: Some(64 * 1024 * 1024),
16248                ..Default::default()
16249            }),
16250            Some(LimitsSpec {
16251                memory: Some(64 * 1024 * 1024),
16252                fuel: Some(1_000_000),
16253                wall_clock: Some(Duration::from_secs(30)),
16254                cpu: Some(500),
16255            }),
16256        ];
16257        for limits in fixtures {
16258            let c = caixa_with_limits(limits.clone());
16259            assert_eq!(
16260                c.limits(),
16261                limits.as_ref(),
16262                "Caixa::limits must return :limits verbatim (got {:?}, \
16263                 expected {:?})",
16264                c.limits(),
16265                limits.as_ref(),
16266            );
16267            match (c.limits(), c.limits.as_ref()) {
16268                (Some(a), Some(b)) => assert!(
16269                    std::ptr::eq(a, b),
16270                    "Caixa::limits accessor and self.limits.as_ref() \
16271                     field access must borrow the same backing storage \
16272                     — the accessor is the substrate-primitive typed \
16273                     dispatch every downstream Servico-M2-overlay \
16274                     composite consumer must route through, and a \
16275                     reference-identity split would silently break \
16276                     every consumer that relied on the borrow sharing \
16277                     the composite's storage",
16278                ),
16279                (None, None) => {}
16280                _ => panic!(
16281                    "Caixa::limits presence bit must byte-equal \
16282                     self.limits.is_some() — a presence-bit drift would \
16283                     silently split the paired StandardLayout::verify \
16284                     per-`:limits` shape gate's traversal head from \
16285                     the peer render::servico_m2_overlay M2 overlay \
16286                     emitter's traversal head from the peer \
16287                     Caixa::declared_servico_slots M2 declared-slot \
16288                     enumerator's presence probe",
16289                ),
16290            }
16291            assert_eq!(
16292                c.limits().is_some(),
16293                c.limits.is_some(),
16294                "Caixa::limits().is_some() must byte-equal \
16295                 self.limits.is_some() — a presence-bit drift would \
16296                 silently split every downstream Option<&LimitsSpec> \
16297                 consumer's partition on the engine-default arm",
16298            );
16299        }
16300    }
16301
16302    #[test]
16303    fn declared_servico_slots_limits_arm_routes_through_accessor() {
16304        // Composition pin: [`Caixa::declared_servico_slots`]'s
16305        // `:limits` presence-probe arm must key off [`Caixa::limits`],
16306        // not the raw `self.limits.is_some()` field-probe. Structurally:
16307        // a `Caixa { limits: Some(LimitsSpec::default()), .. }` must
16308        // still push `M2_AUTHOR_KEY_LIMITS` onto the declared-slot list
16309        // (the presence bit is `Some`, so the M2 kind-coherence gate
16310        // must surface the slot as "declared" even when every per-axis
16311        // cap is unset), and a `Caixa { limits: None, .. }` must NOT
16312        // push the label (the "author omitted the slot entirely"
16313        // partition). The pair jointly pins the accessor + declared-
16314        // slot enumerator composition: any future silent detour that
16315        // had the accessor collapse `Some(LimitsSpec::default())` to
16316        // `None` (a `.filter(|l| !l.is_empty())` projection) would
16317        // silently absorb the "declared but empty" arm at the
16318        // accessor boundary and the [`crate::LayoutError::ServicoSlotsOnNonServico`]
16319        // kind-coherence gate would silently accept a
16320        // struct-literal `Caixa` carrying the drift.
16321        //
16322        // Peer of the sibling per-`Caixa`
16323        // `validate_deps_duplicate_arm_routes_through_accessor` (ad34b4e)
16324        // and `validate_deps_duplicate_deps_dev_arm_routes_through_accessor`
16325        // (f7fd81e) accessor-composition pins on the sibling `:deps` /
16326        // `:deps-dev` outer-`&[Dep]`-composition axes — same "the
16327        // enumerator gate must route through the substrate-primitive
16328        // typed dispatch" discipline extended onto the outer top-level
16329        // [`Caixa`] `Option<&LimitsSpec>`-composition surface, opening
16330        // the outer-`Caixa` M2 Servico-runtime-slot arm of the
16331        // composition-pin family.
16332        use crate::LimitsSpec;
16333        let c = caixa_with_limits(Some(LimitsSpec::default()));
16334        let slots = c.declared_servico_slots();
16335        assert!(
16336            slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
16337            "declared_servico_slots must push M2_AUTHOR_KEY_LIMITS \
16338             when `:limits` is Some (even for LimitsSpec::default()) \
16339             — the accessor and the enumerator gate must route through \
16340             the same substrate-primitive typed dispatch on the outer \
16341             :limits presence bit (got slots={slots:?})",
16342        );
16343        let c = caixa_with_limits(None);
16344        let slots = c.declared_servico_slots();
16345        assert!(
16346            !slots.contains(&crate::render::M2_AUTHOR_KEY_LIMITS),
16347            "declared_servico_slots must NOT push M2_AUTHOR_KEY_LIMITS \
16348             when `:limits` is None — the author-omitted arm must \
16349             route through the accessor's None-return unchanged (got \
16350             slots={slots:?})",
16351        );
16352    }
16353
16354    #[test]
16355    fn servico_m2_overlay_limits_arm_routes_through_accessor() {
16356        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16357        // per-`:limits` M2 overlay emit arm must key off
16358        // [`Caixa::limits`], not the raw `&caixa.limits` field-borrow.
16359        // Structurally: a `Caixa { limits: Some(LimitsSpec { memory:
16360        // Some(64 MiB), .. default }), .. }` must surface the
16361        // `M2_KEY_LIMITS` key with the per-axis
16362        // `memory: "64MiB"` sub-mapping in the overlay, a `Caixa {
16363        // limits: Some(LimitsSpec::default()), .. }` must omit the
16364        // key entirely (the `.is_empty()`-gated inner arm elides an
16365        // empty composite even when the outer presence bit is `Some`),
16366        // and a `Caixa { limits: None, .. }` must also omit the key
16367        // (the "author omitted the slot entirely" partition). The
16368        // three-fixture family jointly pins the accessor + M2 overlay
16369        // emitter composition: any future silent detour that had the
16370        // accessor return a fresh-cloned copy on the `Some` arm (a
16371        // `LimitsSpec::clone()` projection) would silently break the
16372        // reference-identity pin the peer per-axis
16373        // `serde_yaml::to_value(limits)` projection reads from.
16374        use crate::LimitsSpec;
16375        use crate::render::{M2_KEY_LIMITS, servico_m2_overlay};
16376        let c = caixa_with_limits(Some(LimitsSpec {
16377            memory: Some(64 * 1024 * 1024),
16378            ..Default::default()
16379        }));
16380        let overlay = servico_m2_overlay(&c).unwrap();
16381        assert!(
16382            overlay.contains_key(M2_KEY_LIMITS),
16383            "servico_m2_overlay must surface M2_KEY_LIMITS when \
16384             `:limits` carries a non-empty composite — the accessor \
16385             and the M2 overlay emitter must route through the same \
16386             substrate-primitive typed dispatch on the outer :limits \
16387             composite (got overlay={overlay:?})",
16388        );
16389        let c = caixa_with_limits(Some(LimitsSpec::default()));
16390        let overlay = servico_m2_overlay(&c).unwrap();
16391        assert!(
16392            !overlay.contains_key(M2_KEY_LIMITS),
16393            "servico_m2_overlay must omit M2_KEY_LIMITS when \
16394             `:limits` is Some(LimitsSpec::default()) — the empty \
16395             composite's `.is_empty()`-gated inner arm must elide \
16396             the key regardless of the outer presence bit (got \
16397             overlay={overlay:?})",
16398        );
16399        let c = caixa_with_limits(None);
16400        let overlay = servico_m2_overlay(&c).unwrap();
16401        assert!(
16402            !overlay.contains_key(M2_KEY_LIMITS),
16403            "servico_m2_overlay must omit M2_KEY_LIMITS when \
16404             `:limits` is None — the author-omitted arm must route \
16405             through the accessor's None-return unchanged (got \
16406             overlay={overlay:?})",
16407        );
16408    }
16409
16410    #[test]
16411    fn limits_projects_option_ref_by_borrow() {
16412        // The by-borrow pin: [`Caixa::limits`] returns
16413        // `Option<&LimitsSpec>` by borrow — the returned reference
16414        // borrows the underlying `Option<LimitsSpec>` storage of the
16415        // `:limits` slot and the accessor must not clone the backing
16416        // composite on every call. Peer of the sibling
16417        // `deps_projects_slice_by_borrow` (ad34b4e) /
16418        // `deps_dev_projects_slice_by_borrow` (f7fd81e) by-borrow pins
16419        // on the outer top-level [`Caixa`] `&[Dep]`-return axes —
16420        // extended here to the outer [`Caixa`] `Option<&Composite>`-
16421        // return axis: the accessor's returned reference must borrow
16422        // from `&self` (the returned reference's lifetime is tied to
16423        // `&self`), and calling the accessor twice on the same
16424        // [`Caixa`] must yield references that are pointer-equal (the
16425        // underlying byte-buffer is the storage `LimitsSpec`'s
16426        // allocation, not a fresh copy) as well as value-equal
16427        // (idempotent, no side effects on `&self`).
16428        //
16429        // Pins against a future silent detour that returned an owned
16430        // `LimitsSpec` (which would type-check via the `Clone` impl
16431        // but silently clone on every call), a `&LimitsSpec` panic-
16432        // return on the `None` arm (which would collapse the load-
16433        // bearing `Option` presence-bit into a runtime panic), or a
16434        // one-arm-only accessor that returned a saturating composite
16435        // on some sentinel input.
16436        use crate::LimitsSpec;
16437        use std::time::Duration;
16438        for limits in [
16439            Some(LimitsSpec::default()),
16440            Some(LimitsSpec {
16441                memory: Some(64 * 1024 * 1024),
16442                fuel: Some(1_000_000),
16443                wall_clock: Some(Duration::from_secs(30)),
16444                cpu: Some(500),
16445            }),
16446        ] {
16447            let c = caixa_with_limits(limits.clone());
16448            let first = c.limits().unwrap();
16449            let second = c.limits().unwrap();
16450            assert_eq!(
16451                first, second,
16452                "Caixa::limits must be idempotent — two successive \
16453                 calls on the same &self must return the same \
16454                 &LimitsSpec",
16455            );
16456            assert!(
16457                std::ptr::eq(first, second),
16458                "Caixa::limits must borrow the underlying \
16459                 Option<LimitsSpec> storage — two successive calls \
16460                 must return references with the same backing pointer \
16461                 (a fresh LimitsSpec clone would change the pointer \
16462                 on every call)",
16463            );
16464            assert_eq!(
16465                Some(first),
16466                limits.as_ref(),
16467                "Caixa::limits must return :limits verbatim by borrow \
16468                 — got {first:?}, expected {:?}",
16469                limits.as_ref(),
16470            );
16471        }
16472        let c = caixa_with_limits(None);
16473        assert!(
16474            c.limits().is_none(),
16475            "Caixa::limits must return None when :limits is absent — \
16476             the author-omitted arm must project through the \
16477             accessor's Option::None unchanged",
16478        );
16479    }
16480
16481    // ── Caixa::behavior — outer top-level Option<&BehaviorSpec> composite-reference accessor ──
16482
16483    fn caixa_with_behavior(behavior: Option<crate::BehaviorSpec>) -> Caixa {
16484        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16485        c.behavior = behavior;
16486        c
16487    }
16488
16489    #[test]
16490    fn behavior_returns_behavior_option_ref_verbatim_across_permutations() {
16491        // The canonical per-`Caixa` `:behavior` M2 typed-slot outer-
16492        // composite optional-composite-reference-shape pin:
16493        // [`Caixa::behavior`] must return the `:behavior` typed
16494        // `Option<BehaviorSpec>` verbatim as an `Option<&BehaviorSpec>`
16495        // reference over the same backing storage the raw
16496        // `self.behavior.as_ref()` field access borrows from, byte-equal
16497        // across every representative fixture in the accept-set — the
16498        // author-omitted `None` shape (the "runtime-default applies"
16499        // partition every downstream Servico M2 overlay emitter treats
16500        // as "emit nothing"), the empty-composite `Some(BehaviorSpec {
16501        // .. default })` shape ([`BehaviorSpec::is_empty`] holds —
16502        // every per-callback path is `None`, so the peer M2 overlay
16503        // emitter's `.is_empty()`-gated projection still emits nothing
16504        // but the outer presence-bit is `Some`, so
16505        // [`Caixa::declared_servico_slots`] still pushes the
16506        // `M2_AUTHOR_KEY_BEHAVIOR` label), a single-callback fixture
16507        // (only `:on-state-change` set — the canonical shape a caixa
16508        // that only wires the hot-upgrade migration path carries), and
16509        // a fully-populated composite (every per-callback path set —
16510        // the canonical shape a fully-instrumented gen_server-shaped
16511        // Servico carries).
16512        //
16513        // Peer of the sibling
16514        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16515        // (b2bd9d7) opening fixture-family + reference-identity +
16516        // presence-bit tetrad pin on the outer top-level [`Caixa`]
16517        // `Option<&Composite>`-return sub-family — extended here to the
16518        // second axis of that sub-family so both of the currently-lifted
16519        // M2 Servico-runtime `Option<&Composite>` slots (`:limits` /
16520        // `:behavior`) carry the same "byte-equal, borrow-shared,
16521        // presence-bit-preserved" outer-accessor discipline.
16522        //
16523        // Pins against a future silent detour that returned a fresh-
16524        // cloned [`crate::BehaviorSpec`] copy (which would type-check
16525        // via the `Clone` impl but silently break every downstream
16526        // caller that relied on the reference sharing the composite's
16527        // backing identity), a reference to an operator-resolved
16528        // overlay (a future per-cluster `:behavior-overrides` slot —
16529        // its resolution must land at exactly this accessor body, not
16530        // silently divert the raw slot away from a second consumer), a
16531        // `None` → `Some(BehaviorSpec::default)` cluster-default
16532        // projection (which would collapse the load-bearing
16533        // "author-omitted `:behavior` ⇒ runtime-default applies"
16534        // partition the peer [`crate::render::servico_m2_overlay`]
16535        // emitter, the peer [`Caixa::declared_servico_slots`]
16536        // enumerator, and the cross-slot
16537        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
16538        // gate all read), or a callback-shuffled projection (a future
16539        // detour that swapped `on_init` and `on_terminate` through the
16540        // accessor would silently split the paired
16541        // [`crate::StandardLayout::verify`] per-`:behavior` shape gate's
16542        // traversal input from the peer `servico_m2_overlay` emitter's
16543        // projection input from the cross-slot `:state-change`
16544        // composition gate's traversal input).
16545        use crate::BehaviorSpec;
16546        use std::path::PathBuf;
16547        let fixtures: Vec<Option<BehaviorSpec>> = vec![
16548            None,
16549            Some(BehaviorSpec::default()),
16550            Some(BehaviorSpec {
16551                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16552                ..Default::default()
16553            }),
16554            Some(BehaviorSpec {
16555                on_init: Some(PathBuf::from("lib/init.lisp")),
16556                on_call: Some(PathBuf::from("lib/handlers.lisp")),
16557                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
16558                on_info: Some(PathBuf::from("lib/handlers.lisp")),
16559                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16560                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
16561            }),
16562        ];
16563        for behavior in fixtures {
16564            let c = caixa_with_behavior(behavior.clone());
16565            assert_eq!(
16566                c.behavior(),
16567                behavior.as_ref(),
16568                "Caixa::behavior must return :behavior verbatim (got \
16569                 {:?}, expected {:?})",
16570                c.behavior(),
16571                behavior.as_ref(),
16572            );
16573            match (c.behavior(), c.behavior.as_ref()) {
16574                (Some(a), Some(b)) => assert!(
16575                    std::ptr::eq(a, b),
16576                    "Caixa::behavior accessor and self.behavior.as_ref() \
16577                     field access must borrow the same backing storage \
16578                     — the accessor is the substrate-primitive typed \
16579                     dispatch every downstream Servico-M2-overlay \
16580                     composite consumer must route through, and a \
16581                     reference-identity split would silently break \
16582                     every consumer that relied on the borrow sharing \
16583                     the composite's storage",
16584                ),
16585                (None, None) => {}
16586                _ => panic!(
16587                    "Caixa::behavior presence bit must byte-equal \
16588                     self.behavior.is_some() — a presence-bit drift \
16589                     would silently split the paired \
16590                     StandardLayout::verify per-`:behavior` shape \
16591                     gate's traversal head from the peer \
16592                     render::servico_m2_overlay M2 overlay emitter's \
16593                     traversal head from the cross-slot \
16594                     validate_upgrade_from_against_behavior \
16595                     composition gate's traversal head from the peer \
16596                     Caixa::declared_servico_slots M2 declared-slot \
16597                     enumerator's presence probe",
16598                ),
16599            }
16600            assert_eq!(
16601                c.behavior().is_some(),
16602                c.behavior.is_some(),
16603                "Caixa::behavior().is_some() must byte-equal \
16604                 self.behavior.is_some() — a presence-bit drift would \
16605                 silently split every downstream Option<&BehaviorSpec> \
16606                 consumer's partition on the runtime-default arm",
16607            );
16608        }
16609    }
16610
16611    #[test]
16612    fn declared_servico_slots_behavior_arm_routes_through_accessor() {
16613        // Composition pin: [`Caixa::declared_servico_slots`]'s
16614        // `:behavior` presence-probe arm must key off
16615        // [`Caixa::behavior`], not the raw `self.behavior.is_some()`
16616        // field-probe. Structurally: a `Caixa { behavior:
16617        // Some(BehaviorSpec::default()), .. }` must still push
16618        // `M2_AUTHOR_KEY_BEHAVIOR` onto the declared-slot list (the
16619        // presence bit is `Some`, so the M2 kind-coherence gate must
16620        // surface the slot as "declared" even when every per-callback
16621        // path is unset), and a `Caixa { behavior: None, .. }` must
16622        // NOT push the label (the "author omitted the slot entirely"
16623        // partition). The pair jointly pins the accessor + declared-
16624        // slot enumerator composition: any future silent detour that
16625        // had the accessor collapse `Some(BehaviorSpec::default())`
16626        // to `None` (a `.filter(|b| !b.is_empty())` projection) would
16627        // silently absorb the "declared but empty" arm at the
16628        // accessor boundary and the
16629        // [`crate::LayoutError::ServicoSlotsOnNonServico`]
16630        // kind-coherence gate would silently accept a struct-literal
16631        // `Caixa` carrying the drift.
16632        //
16633        // Peer of the sibling
16634        // `declared_servico_slots_limits_arm_routes_through_accessor`
16635        // (b2bd9d7) composition pin on the sibling `:limits` outer-
16636        // `Option<&LimitsSpec>` arm of the same
16637        // [`Caixa::declared_servico_slots`] M2 declared-slot
16638        // enumerator's traversal — same "the enumerator gate must
16639        // route through the substrate-primitive typed dispatch"
16640        // discipline extended onto the outer top-level [`Caixa`]
16641        // `Option<&BehaviorSpec>`-composition surface.
16642        use crate::BehaviorSpec;
16643        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
16644        let slots = c.declared_servico_slots();
16645        assert!(
16646            slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
16647            "declared_servico_slots must push M2_AUTHOR_KEY_BEHAVIOR \
16648             when `:behavior` is Some (even for BehaviorSpec::default()) \
16649             — the accessor and the enumerator gate must route through \
16650             the same substrate-primitive typed dispatch on the outer \
16651             :behavior presence bit (got slots={slots:?})",
16652        );
16653        let c = caixa_with_behavior(None);
16654        let slots = c.declared_servico_slots();
16655        assert!(
16656            !slots.contains(&crate::render::M2_AUTHOR_KEY_BEHAVIOR),
16657            "declared_servico_slots must NOT push M2_AUTHOR_KEY_BEHAVIOR \
16658             when `:behavior` is None — the author-omitted arm must \
16659             route through the accessor's None-return unchanged (got \
16660             slots={slots:?})",
16661        );
16662    }
16663
16664    #[test]
16665    fn servico_m2_overlay_behavior_arm_routes_through_accessor() {
16666        // Composition pin: [`crate::render::servico_m2_overlay`]'s
16667        // per-`:behavior` M2 overlay emit arm must key off
16668        // [`Caixa::behavior`], not the raw `&caixa.behavior`
16669        // field-borrow. Structurally: a `Caixa { behavior:
16670        // Some(BehaviorSpec { on_state_change: Some(...), .. default
16671        // }), .. }` must surface the `M2_KEY_BEHAVIOR` key with the
16672        // per-callback `onStateChange` sub-mapping in the overlay, a
16673        // `Caixa { behavior: Some(BehaviorSpec::default()), .. }`
16674        // must omit the key entirely (the `.is_empty()`-gated inner
16675        // arm elides an empty composite even when the outer presence
16676        // bit is `Some`), and a `Caixa { behavior: None, .. }` must
16677        // also omit the key (the "author omitted the slot entirely"
16678        // partition). The three-fixture family jointly pins the
16679        // accessor + M2 overlay emitter composition: any future
16680        // silent detour that had the accessor return a fresh-cloned
16681        // copy on the `Some` arm (a `BehaviorSpec::clone()`
16682        // projection) would silently break the reference-identity
16683        // pin the peer per-callback `serde_yaml::to_value(behavior)`
16684        // projection reads from.
16685        //
16686        // Peer of the sibling
16687        // `servico_m2_overlay_limits_arm_routes_through_accessor`
16688        // (b2bd9d7) composition pin on the sibling `:limits` outer-
16689        // `Option<&LimitsSpec>` arm of the same
16690        // [`crate::render::servico_m2_overlay`] M2 overlay emitter's
16691        // traversal — same "the emitter must route through the
16692        // substrate-primitive typed dispatch on the outer composite"
16693        // discipline extended onto the outer top-level [`Caixa`]
16694        // `Option<&BehaviorSpec>`-composition surface.
16695        use crate::BehaviorSpec;
16696        use crate::render::{M2_KEY_BEHAVIOR, servico_m2_overlay};
16697        use std::path::PathBuf;
16698        let c = caixa_with_behavior(Some(BehaviorSpec {
16699            on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16700            ..Default::default()
16701        }));
16702        let overlay = servico_m2_overlay(&c).unwrap();
16703        assert!(
16704            overlay.contains_key(M2_KEY_BEHAVIOR),
16705            "servico_m2_overlay must surface M2_KEY_BEHAVIOR when \
16706             `:behavior` carries a non-empty composite — the accessor \
16707             and the M2 overlay emitter must route through the same \
16708             substrate-primitive typed dispatch on the outer :behavior \
16709             composite (got overlay={overlay:?})",
16710        );
16711        let c = caixa_with_behavior(Some(BehaviorSpec::default()));
16712        let overlay = servico_m2_overlay(&c).unwrap();
16713        assert!(
16714            !overlay.contains_key(M2_KEY_BEHAVIOR),
16715            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
16716             `:behavior` is Some(BehaviorSpec::default()) — the empty \
16717             composite's `.is_empty()`-gated inner arm must elide the \
16718             key regardless of the outer presence bit (got \
16719             overlay={overlay:?})",
16720        );
16721        let c = caixa_with_behavior(None);
16722        let overlay = servico_m2_overlay(&c).unwrap();
16723        assert!(
16724            !overlay.contains_key(M2_KEY_BEHAVIOR),
16725            "servico_m2_overlay must omit M2_KEY_BEHAVIOR when \
16726             `:behavior` is None — the author-omitted arm must route \
16727             through the accessor's None-return unchanged (got \
16728             overlay={overlay:?})",
16729        );
16730    }
16731
16732    #[test]
16733    fn behavior_projects_option_ref_by_borrow() {
16734        // The by-borrow pin: [`Caixa::behavior`] returns
16735        // `Option<&BehaviorSpec>` by borrow — the returned reference
16736        // borrows the underlying `Option<BehaviorSpec>` storage of the
16737        // `:behavior` slot and the accessor must not clone the backing
16738        // composite on every call. Peer of the sibling
16739        // `limits_projects_option_ref_by_borrow` (b2bd9d7) by-borrow
16740        // pin on the outer top-level [`Caixa`] `Option<&Composite>`-
16741        // return sub-family — extended here to the second axis of the
16742        // same sub-family: the accessor's returned reference must
16743        // borrow from `&self` (the returned reference's lifetime is
16744        // tied to `&self`), and calling the accessor twice on the same
16745        // [`Caixa`] must yield references that are pointer-equal (the
16746        // underlying byte-buffer is the storage `BehaviorSpec`'s
16747        // allocation, not a fresh copy) as well as value-equal
16748        // (idempotent, no side effects on `&self`).
16749        //
16750        // Pins against a future silent detour that returned an owned
16751        // `BehaviorSpec` (which would type-check via the `Clone` impl
16752        // but silently clone on every call), a `&BehaviorSpec` panic-
16753        // return on the `None` arm (which would collapse the load-
16754        // bearing `Option` presence-bit into a runtime panic), or a
16755        // one-arm-only accessor that returned a saturating composite
16756        // on some sentinel input.
16757        use crate::BehaviorSpec;
16758        use std::path::PathBuf;
16759        for behavior in [
16760            Some(BehaviorSpec::default()),
16761            Some(BehaviorSpec {
16762                on_init: Some(PathBuf::from("lib/init.lisp")),
16763                on_call: Some(PathBuf::from("lib/handlers.lisp")),
16764                on_cast: Some(PathBuf::from("lib/handlers.lisp")),
16765                on_info: Some(PathBuf::from("lib/handlers.lisp")),
16766                on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
16767                on_terminate: Some(PathBuf::from("lib/cleanup.lisp")),
16768            }),
16769        ] {
16770            let c = caixa_with_behavior(behavior.clone());
16771            let first = c.behavior().unwrap();
16772            let second = c.behavior().unwrap();
16773            assert_eq!(
16774                first, second,
16775                "Caixa::behavior must be idempotent — two successive \
16776                 calls on the same &self must return the same \
16777                 &BehaviorSpec",
16778            );
16779            assert!(
16780                std::ptr::eq(first, second),
16781                "Caixa::behavior must borrow the underlying \
16782                 Option<BehaviorSpec> storage — two successive calls \
16783                 must return references with the same backing pointer \
16784                 (a fresh BehaviorSpec clone would change the pointer \
16785                 on every call)",
16786            );
16787            assert_eq!(
16788                Some(first),
16789                behavior.as_ref(),
16790                "Caixa::behavior must return :behavior verbatim by \
16791                 borrow — got {first:?}, expected {:?}",
16792                behavior.as_ref(),
16793            );
16794        }
16795        let c = caixa_with_behavior(None);
16796        assert!(
16797            c.behavior().is_none(),
16798            "Caixa::behavior must return None when :behavior is absent \
16799             — the author-omitted arm must project through the \
16800             accessor's Option::None unchanged",
16801        );
16802    }
16803
16804    // ── Caixa::politicas — outer top-level Option<&MeshPolicy> composite-reference accessor ──
16805
16806    fn caixa_aplicacao_with_politicas(politicas: Option<crate::aplicacao::MeshPolicy>) -> Caixa {
16807        use crate::aplicacao::{Membro, WitContract};
16808        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
16809        c.kind = CaixaKind::Aplicacao;
16810        c.membros = vec![Membro {
16811            caixa: "a".into(),
16812            versao: "^0.1".into(),
16813        }];
16814        c.contratos = vec![WitContract {
16815            de: "a".into(),
16816            para: "a".into(),
16817            wit: "wasi:http/proxy".into(),
16818            endpoint: Some("/x".into()),
16819            subject: None,
16820            slot: None,
16821        }];
16822        c.politicas = politicas;
16823        c
16824    }
16825
16826    #[test]
16827    fn politicas_returns_politicas_option_ref_verbatim_across_permutations() {
16828        // The canonical per-`Caixa` `:politicas` M3 mesh-slot outer-
16829        // composite optional-composite-reference-shape pin:
16830        // [`Caixa::politicas`] must return the `:politicas` typed
16831        // `Option<MeshPolicy>` verbatim as an `Option<&MeshPolicy>`
16832        // reference over the same backing storage the raw
16833        // `self.politicas.as_ref()` field access borrows from,
16834        // byte-equal across every representative fixture in the
16835        // accept-set — the author-omitted `None` shape (the "cluster-
16836        // default applies" partition every downstream mesh-artifact
16837        // emitter treats as "emit no `:politicas` overlay"), the
16838        // empty-composite `Some(MeshPolicy { .. default })` shape
16839        // ([`crate::aplicacao::MeshPolicy::is_empty`] holds — every
16840        // per-axis mesh-policy scalar is `None`, so the peer inner
16841        // [`crate::AplicacaoSpec::politicas`] `.is_empty()`-gated
16842        // caixa-mesh overlay elides every per-axis emit but the outer
16843        // presence-bit is `Some`, so [`Caixa::declared_mesh_slots`]
16844        // still pushes the `M3_AUTHOR_KEY_POLITICAS` label), a
16845        // single-axis fixture (only `:timeout` set — the canonical
16846        // shape a latency-sensitive Aplicacao carries), and a
16847        // fully-populated composite (every per-axis mesh-policy
16848        // scalar set — the canonical shape a fully-governed
16849        // Aplicacao carries).
16850        //
16851        // Pins against a future silent detour that returned a fresh-
16852        // cloned [`crate::aplicacao::MeshPolicy`] copy (which would
16853        // type-check via the `Clone` impl but silently break every
16854        // downstream caller that relied on the reference sharing the
16855        // composite's backing identity), a reference to an operator-
16856        // resolved overlay (the future per-cluster
16857        // `:politicas-overrides` slot — its resolution must land at
16858        // exactly this accessor body, not silently divert the raw
16859        // slot away from the peer [`Caixa::declared_mesh_slots`]
16860        // enumerator's presence probe), a
16861        // `None` → `Some(MeshPolicy::default)` cluster-default
16862        // projection (which would collapse the load-bearing
16863        // "author-omitted `:politicas` ⇒ cluster-default applies"
16864        // partition the peer [`Caixa::declared_mesh_slots`]
16865        // enumerator and the peer [`Caixa::aplicacao_view`]
16866        // Aplicacao-composition seed both read), or an axis-shuffled
16867        // projection (a future detour that swapped `timeout` and
16868        // `retries` through the accessor would silently split the
16869        // paired [`Caixa::aplicacao_view`] seed's fold input from the
16870        // sibling M3 mesh-artifact emitter's projection input).
16871        //
16872        // Third outer top-level [`Caixa`] `Option<&Composite>`-return
16873        // composite-reference accessor pin on the substrate primitive
16874        // — peer of the sibling
16875        // `limits_returns_limits_option_ref_verbatim_across_permutations`
16876        // (b2bd9d7) and
16877        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
16878        // (35d8b52) opening tetrad pins on the outer top-level
16879        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
16880        // here to the first of the three M3 mesh-slot axes so the
16881        // opening third of the outer `Option<&Composite>` sub-family
16882        // carries the same "byte-equal, borrow-shared, presence-bit-
16883        // preserved" outer-accessor discipline.
16884        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
16885        use std::time::Duration;
16886        let fixtures: Vec<Option<MeshPolicy>> = vec![
16887            None,
16888            Some(MeshPolicy::default()),
16889            Some(MeshPolicy {
16890                timeout: Some(Duration::from_secs(30)),
16891                ..Default::default()
16892            }),
16893            Some(MeshPolicy {
16894                timeout: Some(Duration::from_secs(30)),
16895                retries: Some(3),
16896                circuit_breaker: Some(CircuitBreaker {
16897                    max_failures: 5,
16898                    window: Duration::from_secs(60),
16899                }),
16900                mtls_required: Some(true),
16901                rate_limit: Some(RateLimit {
16902                    rate: 100,
16903                    window: Duration::from_secs(1),
16904                }),
16905            }),
16906        ];
16907        for politicas in fixtures {
16908            let c = caixa_aplicacao_with_politicas(politicas.clone());
16909            assert_eq!(
16910                c.politicas(),
16911                politicas.as_ref(),
16912                "Caixa::politicas must return :politicas verbatim (got \
16913                 {:?}, expected {:?})",
16914                c.politicas(),
16915                politicas.as_ref(),
16916            );
16917            match (c.politicas(), c.politicas.as_ref()) {
16918                (Some(a), Some(b)) => assert!(
16919                    std::ptr::eq(a, b),
16920                    "Caixa::politicas accessor and self.politicas.as_ref() \
16921                     field access must borrow the same backing storage \
16922                     — the accessor is the substrate-primitive typed \
16923                     dispatch every downstream Aplicacao-mesh-overlay \
16924                     composite consumer must route through, and a \
16925                     reference-identity split would silently break \
16926                     every consumer that relied on the borrow sharing \
16927                     the composite's storage",
16928                ),
16929                (None, None) => {}
16930                _ => panic!(
16931                    "Caixa::politicas presence bit must byte-equal \
16932                     self.politicas.is_some() — a presence-bit drift \
16933                     would silently split the paired \
16934                     Caixa::aplicacao_view Aplicacao-composition seed's \
16935                     traversal head from the peer \
16936                     Caixa::declared_mesh_slots M3 declared-slot \
16937                     enumerator's presence probe",
16938                ),
16939            }
16940            assert_eq!(
16941                c.politicas().is_some(),
16942                c.politicas.is_some(),
16943                "Caixa::politicas().is_some() must byte-equal \
16944                 self.politicas.is_some() — a presence-bit drift would \
16945                 silently split every downstream Option<&MeshPolicy> \
16946                 consumer's partition on the cluster-default arm",
16947            );
16948        }
16949    }
16950
16951    #[test]
16952    fn declared_mesh_slots_politicas_arm_routes_through_accessor() {
16953        // Composition pin: [`Caixa::declared_mesh_slots`]'s
16954        // `:politicas` presence-probe arm must key off
16955        // [`Caixa::politicas`], not the raw `self.politicas.is_some()`
16956        // field-probe. Structurally: a `Caixa { politicas:
16957        // Some(MeshPolicy::default()), .. }` must still push
16958        // `M3_AUTHOR_KEY_POLITICAS` onto the declared-slot list (the
16959        // presence bit is `Some`, so the M3 kind-coherence gate must
16960        // surface the slot as "declared" even when every per-axis
16961        // scalar is unset), and a `Caixa { politicas: None, .. }` must
16962        // NOT push the label (the "author omitted the slot entirely"
16963        // partition). The pair jointly pins the accessor + declared-
16964        // slot enumerator composition: any future silent detour that
16965        // had the accessor collapse `Some(MeshPolicy::default())` to
16966        // `None` (a `.filter(|p| !p.is_empty())` projection) would
16967        // silently absorb the "declared but empty" arm at the
16968        // accessor boundary and the
16969        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
16970        // coherence gate would silently accept a struct-literal
16971        // `Caixa` carrying the drift.
16972        //
16973        // Peer of the sibling
16974        // `declared_servico_slots_limits_arm_routes_through_accessor`
16975        // (b2bd9d7) and
16976        // `declared_servico_slots_behavior_arm_routes_through_accessor`
16977        // (35d8b52) composition pins on the sibling `:limits` /
16978        // `:behavior` outer-`Option<&Composite>` arms of the peer
16979        // [`Caixa::declared_servico_slots`] M2 declared-slot
16980        // enumerator's traversal — same "the enumerator gate must
16981        // route through the substrate-primitive typed dispatch"
16982        // discipline extended onto the outer top-level [`Caixa`] M3
16983        // mesh-slot family so the [`Caixa::declared_mesh_slots`]
16984        // enumerator carries the same routing invariant as its M2
16985        // sibling.
16986        use crate::aplicacao::MeshPolicy;
16987        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
16988        let slots = c.declared_mesh_slots();
16989        assert!(
16990            slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
16991            "declared_mesh_slots must push M3_AUTHOR_KEY_POLITICAS \
16992             when `:politicas` is Some (even for MeshPolicy::default()) \
16993             — the accessor and the enumerator gate must route through \
16994             the same substrate-primitive typed dispatch on the outer \
16995             :politicas presence bit (got slots={slots:?})",
16996        );
16997        let c = caixa_aplicacao_with_politicas(None);
16998        let slots = c.declared_mesh_slots();
16999        assert!(
17000            !slots.contains(&crate::render::M3_AUTHOR_KEY_POLITICAS),
17001            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_POLITICAS \
17002             when `:politicas` is None — the author-omitted arm must \
17003             route through the accessor's None-return unchanged (got \
17004             slots={slots:?})",
17005        );
17006    }
17007
17008    #[test]
17009    fn aplicacao_view_politicas_arm_folds_through_accessor() {
17010        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:politicas`
17011        // Aplicacao-composition seed must fold through
17012        // [`Caixa::politicas`], not the raw
17013        // `self.politicas.clone().unwrap_or_default()` field-borrow.
17014        // Structurally: a `Caixa { politicas: Some(MeshPolicy {
17015        // timeout: Some(30s), .. default }), kind: Aplicacao, .. }`
17016        // must surface a projected [`crate::AplicacaoSpec`] whose
17017        // `politicas().timeout()` field byte-equals the outer
17018        // composite's `timeout` scalar (the fold must project the
17019        // authored composite verbatim), a `Caixa { politicas:
17020        // Some(MeshPolicy::default()), kind: Aplicacao, .. }` must
17021        // surface an [`crate::AplicacaoSpec`] whose `politicas()`
17022        // byte-equals [`crate::aplicacao::MeshPolicy::default`] (the
17023        // fold's empty-composite arm collapses to the same default the
17024        // author-omitted arm does), and a `Caixa { politicas: None,
17025        // kind: Aplicacao, .. }` must surface an
17026        // [`crate::AplicacaoSpec`] whose `politicas()` byte-equals
17027        // [`crate::aplicacao::MeshPolicy::default`] (the "author
17028        // omitted the slot entirely" arm folds through the
17029        // `unwrap_or_default` onto the cluster-default). The triad
17030        // jointly pins the accessor + Aplicacao-composition seed
17031        // composition: any future silent detour that had the accessor
17032        // divert the raw slot away from the seed's fold (an operator-
17033        // resolved overlay's default-fold arm silently differing from
17034        // the raw slot's default-fold arm) would silently split the
17035        // build-time mesh-artifact emission gate from the caixa-mesh
17036        // renderer's Aplicacao-view input at the composition boundary.
17037        use crate::aplicacao::MeshPolicy;
17038        use std::time::Duration;
17039        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy {
17040            timeout: Some(Duration::from_secs(30)),
17041            ..Default::default()
17042        }));
17043        let view = c.aplicacao_view().unwrap();
17044        assert_eq!(
17045            view.politicas().timeout(),
17046            Some(Duration::from_secs(30)),
17047            "Caixa::aplicacao_view must fold the authored :politicas \
17048             :timeout scalar through the accessor verbatim onto the \
17049             projected AplicacaoSpec — a future silent detour at the \
17050             seed's fold arm would surface here as a projected-scalar \
17051             drift (got {:?})",
17052            view.politicas().timeout(),
17053        );
17054        let c = caixa_aplicacao_with_politicas(Some(MeshPolicy::default()));
17055        let view = c.aplicacao_view().unwrap();
17056        assert_eq!(
17057            view.politicas(),
17058            &MeshPolicy::default(),
17059            "Caixa::aplicacao_view must fold Some(MeshPolicy::default()) \
17060             through the accessor onto MeshPolicy::default — the empty- \
17061             composite arm collapses to the same default the author- \
17062             omitted arm does (got {:?})",
17063            view.politicas(),
17064        );
17065        let c = caixa_aplicacao_with_politicas(None);
17066        let view = c.aplicacao_view().unwrap();
17067        assert_eq!(
17068            view.politicas(),
17069            &MeshPolicy::default(),
17070            "Caixa::aplicacao_view must fold None through the accessor's \
17071             unwrap_or_default onto MeshPolicy::default — the author- \
17072             omitted arm must route through the accessor's None-return \
17073             unchanged (got {:?})",
17074            view.politicas(),
17075        );
17076    }
17077
17078    #[test]
17079    fn politicas_projects_option_ref_by_borrow() {
17080        // The by-borrow pin: [`Caixa::politicas`] returns
17081        // `Option<&MeshPolicy>` by borrow — the returned reference
17082        // borrows the underlying `Option<MeshPolicy>` storage of the
17083        // `:politicas` slot and the accessor must not clone the
17084        // backing composite on every call. Peer of the sibling
17085        // `limits_projects_option_ref_by_borrow` (b2bd9d7) and
17086        // `behavior_projects_option_ref_by_borrow` (35d8b52) by-borrow
17087        // pins on the outer top-level [`Caixa`]
17088        // `Option<&Composite>`-return sub-family — extended here to
17089        // the third axis of the same sub-family: the accessor's
17090        // returned reference must borrow from `&self` (the returned
17091        // reference's lifetime is tied to `&self`), and calling the
17092        // accessor twice on the same [`Caixa`] must yield references
17093        // that are pointer-equal (the underlying byte-buffer is the
17094        // storage `MeshPolicy`'s allocation, not a fresh copy) as
17095        // well as value-equal (idempotent, no side effects on
17096        // `&self`).
17097        //
17098        // Pins against a future silent detour that returned an owned
17099        // `MeshPolicy` (which would type-check via the `Clone` impl
17100        // but silently clone on every call), a `&MeshPolicy` panic-
17101        // return on the `None` arm (which would collapse the load-
17102        // bearing `Option` presence-bit into a runtime panic), or a
17103        // one-arm-only accessor that returned a saturating composite
17104        // on some sentinel input.
17105        use crate::aplicacao::{CircuitBreaker, MeshPolicy, RateLimit};
17106        use std::time::Duration;
17107        for politicas in [
17108            Some(MeshPolicy::default()),
17109            Some(MeshPolicy {
17110                timeout: Some(Duration::from_secs(30)),
17111                retries: Some(3),
17112                circuit_breaker: Some(CircuitBreaker {
17113                    max_failures: 5,
17114                    window: Duration::from_secs(60),
17115                }),
17116                mtls_required: Some(true),
17117                rate_limit: Some(RateLimit {
17118                    rate: 100,
17119                    window: Duration::from_secs(1),
17120                }),
17121            }),
17122        ] {
17123            let c = caixa_aplicacao_with_politicas(politicas.clone());
17124            let first = c.politicas().unwrap();
17125            let second = c.politicas().unwrap();
17126            assert_eq!(
17127                first, second,
17128                "Caixa::politicas must be idempotent — two successive \
17129                 calls on the same &self must return the same \
17130                 &MeshPolicy",
17131            );
17132            assert!(
17133                std::ptr::eq(first, second),
17134                "Caixa::politicas must borrow the underlying \
17135                 Option<MeshPolicy> storage — two successive calls \
17136                 must return references with the same backing pointer \
17137                 (a fresh MeshPolicy clone would change the pointer on \
17138                 every call)",
17139            );
17140            assert_eq!(
17141                Some(first),
17142                politicas.as_ref(),
17143                "Caixa::politicas must return :politicas verbatim by \
17144                 borrow — got {first:?}, expected {:?}",
17145                politicas.as_ref(),
17146            );
17147        }
17148        let c = caixa_aplicacao_with_politicas(None);
17149        assert!(
17150            c.politicas().is_none(),
17151            "Caixa::politicas must return None when :politicas is \
17152             absent — the author-omitted arm must project through the \
17153             accessor's Option::None unchanged",
17154        );
17155    }
17156
17157    // ── Caixa::placement — outer top-level Option<&Placement> composite-reference accessor ──
17158
17159    fn caixa_aplicacao_with_placement(placement: Option<crate::aplicacao::Placement>) -> Caixa {
17160        use crate::aplicacao::{Membro, WitContract};
17161        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17162        c.kind = CaixaKind::Aplicacao;
17163        c.membros = vec![Membro {
17164            caixa: "a".into(),
17165            versao: "^0.1".into(),
17166        }];
17167        c.contratos = vec![WitContract {
17168            de: "a".into(),
17169            para: "a".into(),
17170            wit: "wasi:http/proxy".into(),
17171            endpoint: Some("/x".into()),
17172            subject: None,
17173            slot: None,
17174        }];
17175        c.placement = placement;
17176        c
17177    }
17178
17179    #[test]
17180    fn placement_returns_placement_option_ref_verbatim_across_permutations() {
17181        // The canonical per-`Caixa` `:placement` M3 mesh-slot outer-
17182        // composite optional-composite-reference-shape pin:
17183        // [`Caixa::placement`] must return the `:placement` typed
17184        // `Option<Placement>` verbatim as an `Option<&Placement>`
17185        // reference over the same backing storage the raw
17186        // `self.placement.as_ref()` field access borrows from,
17187        // byte-equal across every representative fixture in the
17188        // accept-set — the author-omitted `None` shape (the
17189        // "cluster-default applies" partition every downstream mesh-
17190        // artifact emitter treats as "emit no `:placement` overlay"),
17191        // the empty-composite `Some(Placement { .. default })` shape
17192        // (`estrategia: SingleNode`, empty clusters, no shard-key /
17193        // affinity — the outer presence-bit is `Some` so
17194        // [`Caixa::declared_mesh_slots`] still pushes the
17195        // `M3_AUTHOR_KEY_PLACEMENT` label), a single-axis
17196        // `Replicated`-on-two-clusters fixture (the canonical shape a
17197        // stateless HTTP Aplicacao carries), and a fully-populated
17198        // `Sharded`-with-shard-key-and-affinity fixture (the canonical
17199        // shape a stateful Akka-style cluster-sharding Aplicacao
17200        // carries).
17201        //
17202        // Pins against a future silent detour that returned a fresh-
17203        // cloned [`crate::aplicacao::Placement`] copy (which would
17204        // type-check via the `Clone` impl but silently break every
17205        // downstream caller that relied on the reference sharing the
17206        // composite's backing identity), a reference to an operator-
17207        // resolved overlay (the future per-cluster
17208        // `:placement-overrides` slot — its resolution must land at
17209        // exactly this accessor body, not silently divert the raw
17210        // slot away from the peer [`Caixa::declared_mesh_slots`]
17211        // enumerator's presence probe), a `None` →
17212        // `Some(Placement::default)` cluster-default projection (which
17213        // would collapse the load-bearing "author-omitted `:placement`
17214        // ⇒ cluster-default applies" partition the peer
17215        // [`Caixa::declared_mesh_slots`] enumerator and the peer
17216        // [`Caixa::aplicacao_view`] Aplicacao-composition seed both
17217        // read), or an axis-shuffled projection (a future detour that
17218        // swapped `clusters` and `affinity` through the accessor would
17219        // silently split the paired [`Caixa::aplicacao_view`] seed's
17220        // fold input from the sibling M3 mesh-artifact emitter's
17221        // projection input).
17222        //
17223        // Fourth outer top-level [`Caixa`] `Option<&Composite>`-return
17224        // composite-reference accessor pin on the substrate primitive
17225        // — peer of the sibling
17226        // `limits_returns_limits_option_ref_verbatim_across_permutations`
17227        // (b2bd9d7),
17228        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
17229        // (35d8b52), and
17230        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
17231        // (5d23d29) opening triad pins on the outer top-level
17232        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
17233        // here to the second of the three M3 mesh-slot axes so the
17234        // opening four-fifths of the outer `Option<&Composite>` sub-
17235        // family carries the same "byte-equal, borrow-shared,
17236        // presence-bit-preserved" outer-accessor discipline.
17237        use crate::aplicacao::{Placement, PlacementStrategy};
17238        let fixtures: Vec<Option<Placement>> = vec![
17239            None,
17240            Some(Placement::default()),
17241            Some(Placement {
17242                estrategia: PlacementStrategy::Replicated,
17243                clusters: vec!["rio".into(), "sao-paulo".into()],
17244                affinity: None,
17245                shard_key: None,
17246            }),
17247            Some(Placement {
17248                estrategia: PlacementStrategy::Sharded,
17249                clusters: vec!["rio".into(), "sao-paulo".into(), "brasilia".into()],
17250                affinity: Some("data-locality".into()),
17251                shard_key: Some("$tenantId".into()),
17252            }),
17253        ];
17254        for placement in fixtures {
17255            let c = caixa_aplicacao_with_placement(placement.clone());
17256            assert_eq!(
17257                c.placement(),
17258                placement.as_ref(),
17259                "Caixa::placement must return :placement verbatim (got \
17260                 {:?}, expected {:?})",
17261                c.placement(),
17262                placement.as_ref(),
17263            );
17264            match (c.placement(), c.placement.as_ref()) {
17265                (Some(a), Some(b)) => assert!(
17266                    std::ptr::eq(a, b),
17267                    "Caixa::placement accessor and self.placement.as_ref() \
17268                     field access must borrow the same backing storage \
17269                     — the accessor is the substrate-primitive typed \
17270                     dispatch every downstream Aplicacao-distribution- \
17271                     overlay composite consumer must route through, and \
17272                     a reference-identity split would silently break \
17273                     every consumer that relied on the borrow sharing \
17274                     the composite's storage",
17275                ),
17276                (None, None) => {}
17277                _ => panic!(
17278                    "Caixa::placement presence bit must byte-equal \
17279                     self.placement.is_some() — a presence-bit drift \
17280                     would silently split the paired \
17281                     Caixa::aplicacao_view Aplicacao-composition seed's \
17282                     traversal head from the peer \
17283                     Caixa::declared_mesh_slots M3 declared-slot \
17284                     enumerator's presence probe",
17285                ),
17286            }
17287            assert_eq!(
17288                c.placement().is_some(),
17289                c.placement.is_some(),
17290                "Caixa::placement().is_some() must byte-equal \
17291                 self.placement.is_some() — a presence-bit drift would \
17292                 silently split every downstream Option<&Placement> \
17293                 consumer's partition on the cluster-default arm",
17294            );
17295        }
17296    }
17297
17298    #[test]
17299    fn declared_mesh_slots_placement_arm_routes_through_accessor() {
17300        // Composition pin: [`Caixa::declared_mesh_slots`]'s
17301        // `:placement` presence-probe arm must key off
17302        // [`Caixa::placement`], not the raw `self.placement.is_some()`
17303        // field-probe. Structurally: a `Caixa { placement:
17304        // Some(Placement::default()), .. }` must still push
17305        // `M3_AUTHOR_KEY_PLACEMENT` onto the declared-slot list (the
17306        // presence bit is `Some`, so the M3 kind-coherence gate must
17307        // surface the slot as "declared" even when every per-axis
17308        // scalar defers to the cluster-default arm), and a `Caixa {
17309        // placement: None, .. }` must NOT push the label (the "author
17310        // omitted the slot entirely" partition). The pair jointly pins
17311        // the accessor + declared-slot enumerator composition: any
17312        // future silent detour that had the accessor collapse
17313        // `Some(Placement::default())` to `None` (a `.filter(|p|
17314        // p.clusters().is_empty().not())` projection) would silently
17315        // absorb the "declared but empty" arm at the accessor boundary
17316        // and the [`crate::LayoutError::MeshSlotsOnNonAplicacao`]
17317        // kind-coherence gate would silently accept a struct-literal
17318        // `Caixa` carrying the drift.
17319        //
17320        // Peer of the sibling
17321        // `declared_servico_slots_limits_arm_routes_through_accessor`
17322        // (b2bd9d7),
17323        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17324        // (35d8b52), and
17325        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
17326        // (5d23d29) composition pins on the sibling `:limits` /
17327        // `:behavior` / `:politicas` outer-`Option<&Composite>` arms
17328        // — same "the enumerator gate must route through the
17329        // substrate-primitive typed dispatch" discipline extended onto
17330        // the second of the three M3 mesh-slot axes so the
17331        // [`Caixa::declared_mesh_slots`] enumerator carries the same
17332        // routing invariant on the `:placement` arm as the peer
17333        // `:politicas` arm.
17334        use crate::aplicacao::Placement;
17335        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
17336        let slots = c.declared_mesh_slots();
17337        assert!(
17338            slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
17339            "declared_mesh_slots must push M3_AUTHOR_KEY_PLACEMENT \
17340             when `:placement` is Some (even for Placement::default()) \
17341             — the accessor and the enumerator gate must route through \
17342             the same substrate-primitive typed dispatch on the outer \
17343             :placement presence bit (got slots={slots:?})",
17344        );
17345        let c = caixa_aplicacao_with_placement(None);
17346        let slots = c.declared_mesh_slots();
17347        assert!(
17348            !slots.contains(&crate::render::M3_AUTHOR_KEY_PLACEMENT),
17349            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_PLACEMENT \
17350             when `:placement` is None — the author-omitted arm must \
17351             route through the accessor's None-return unchanged (got \
17352             slots={slots:?})",
17353        );
17354    }
17355
17356    #[test]
17357    fn aplicacao_view_placement_arm_folds_through_accessor() {
17358        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:placement`
17359        // Aplicacao-composition seed must fold through
17360        // [`Caixa::placement`], not the raw
17361        // `self.placement.clone().unwrap_or_default()` field-borrow.
17362        // Structurally: a `Caixa { placement: Some(Placement {
17363        // estrategia: Replicated, clusters: ["rio"], .. default }),
17364        // kind: Aplicacao, .. }` must surface a projected
17365        // [`crate::AplicacaoSpec`] whose `placement().estrategia()` +
17366        // `placement().clusters()` byte-equal the outer composite's
17367        // authored values (the fold must project the authored
17368        // composite verbatim), a `Caixa { placement:
17369        // Some(Placement::default()), kind: Aplicacao, .. }` must
17370        // surface an [`crate::AplicacaoSpec`] whose `placement()`
17371        // byte-equals [`crate::aplicacao::Placement::default`] (the
17372        // fold's empty-composite arm collapses to the same default
17373        // the author-omitted arm does), and a `Caixa { placement:
17374        // None, kind: Aplicacao, .. }` must surface an
17375        // [`crate::AplicacaoSpec`] whose `placement()` byte-equals
17376        // [`crate::aplicacao::Placement::default`] (the "author
17377        // omitted the slot entirely" arm folds through the
17378        // `unwrap_or_default` onto the cluster-default). The triad
17379        // jointly pins the accessor + Aplicacao-composition seed
17380        // composition: any future silent detour that had the accessor
17381        // divert the raw slot away from the seed's fold (an operator-
17382        // resolved overlay's default-fold arm silently differing from
17383        // the raw slot's default-fold arm) would silently split the
17384        // build-time distribution-artifact emission gate from the
17385        // caixa-mesh renderer's Aplicacao-view input at the
17386        // composition boundary.
17387        use crate::aplicacao::{Placement, PlacementStrategy};
17388        let c = caixa_aplicacao_with_placement(Some(Placement {
17389            estrategia: PlacementStrategy::Replicated,
17390            clusters: vec!["rio".into()],
17391            affinity: None,
17392            shard_key: None,
17393        }));
17394        let view = c.aplicacao_view().unwrap();
17395        assert_eq!(
17396            view.placement().estrategia(),
17397            PlacementStrategy::Replicated,
17398            "Caixa::aplicacao_view must fold the authored :placement \
17399             :estrategia scalar through the accessor verbatim onto the \
17400             projected AplicacaoSpec — a future silent detour at the \
17401             seed's fold arm would surface here as a projected-scalar \
17402             drift (got {:?})",
17403            view.placement().estrategia(),
17404        );
17405        assert_eq!(
17406            view.placement().clusters(),
17407            &["rio"],
17408            "Caixa::aplicacao_view must fold the authored :placement \
17409             :clusters list through the accessor verbatim onto the \
17410             projected AplicacaoSpec — a future silent detour at the \
17411             seed's fold arm would surface here as a projected-list \
17412             drift (got {:?})",
17413            view.placement().clusters(),
17414        );
17415        let c = caixa_aplicacao_with_placement(Some(Placement::default()));
17416        let view = c.aplicacao_view().unwrap();
17417        assert_eq!(
17418            view.placement(),
17419            &Placement::default(),
17420            "Caixa::aplicacao_view must fold Some(Placement::default()) \
17421             through the accessor onto Placement::default — the empty- \
17422             composite arm collapses to the same default the author- \
17423             omitted arm does (got {:?})",
17424            view.placement(),
17425        );
17426        let c = caixa_aplicacao_with_placement(None);
17427        let view = c.aplicacao_view().unwrap();
17428        assert_eq!(
17429            view.placement(),
17430            &Placement::default(),
17431            "Caixa::aplicacao_view must fold None through the accessor's \
17432             unwrap_or_default onto Placement::default — the author- \
17433             omitted arm must route through the accessor's None-return \
17434             unchanged (got {:?})",
17435            view.placement(),
17436        );
17437    }
17438
17439    #[test]
17440    fn placement_projects_option_ref_by_borrow() {
17441        // The by-borrow pin: [`Caixa::placement`] returns
17442        // `Option<&Placement>` by borrow — the returned reference
17443        // borrows the underlying `Option<Placement>` storage of the
17444        // `:placement` slot and the accessor must not clone the
17445        // backing composite on every call. Peer of the sibling
17446        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
17447        // `behavior_projects_option_ref_by_borrow` (35d8b52), and
17448        // `politicas_projects_option_ref_by_borrow` (5d23d29) by-borrow
17449        // pins on the outer top-level [`Caixa`]
17450        // `Option<&Composite>`-return sub-family — extended here to
17451        // the fourth axis of the same sub-family: the accessor's
17452        // returned reference must borrow from `&self` (the returned
17453        // reference's lifetime is tied to `&self`), and calling the
17454        // accessor twice on the same [`Caixa`] must yield references
17455        // that are pointer-equal (the underlying byte-buffer is the
17456        // storage `Placement`'s allocation, not a fresh copy) as well
17457        // as value-equal (idempotent, no side effects on `&self`).
17458        //
17459        // Pins against a future silent detour that returned an owned
17460        // `Placement` (which would type-check via the `Clone` impl
17461        // but silently clone on every call), a `&Placement` panic-
17462        // return on the `None` arm (which would collapse the load-
17463        // bearing `Option` presence-bit into a runtime panic), or a
17464        // one-arm-only accessor that returned a saturating composite
17465        // on some sentinel input.
17466        use crate::aplicacao::{Placement, PlacementStrategy};
17467        for placement in [
17468            Some(Placement::default()),
17469            Some(Placement {
17470                estrategia: PlacementStrategy::Sharded,
17471                clusters: vec!["rio".into(), "sao-paulo".into()],
17472                affinity: Some("data-locality".into()),
17473                shard_key: Some("$tenantId".into()),
17474            }),
17475        ] {
17476            let c = caixa_aplicacao_with_placement(placement.clone());
17477            let first = c.placement().unwrap();
17478            let second = c.placement().unwrap();
17479            assert_eq!(
17480                first, second,
17481                "Caixa::placement must be idempotent — two successive \
17482                 calls on the same &self must return the same \
17483                 &Placement",
17484            );
17485            assert!(
17486                std::ptr::eq(first, second),
17487                "Caixa::placement must borrow the underlying \
17488                 Option<Placement> storage — two successive calls \
17489                 must return references with the same backing pointer \
17490                 (a fresh Placement clone would change the pointer on \
17491                 every call)",
17492            );
17493            assert_eq!(
17494                Some(first),
17495                placement.as_ref(),
17496                "Caixa::placement must return :placement verbatim by \
17497                 borrow — got {first:?}, expected {:?}",
17498                placement.as_ref(),
17499            );
17500        }
17501        let c = caixa_aplicacao_with_placement(None);
17502        assert!(
17503            c.placement().is_none(),
17504            "Caixa::placement must return None when :placement is \
17505             absent — the author-omitted arm must project through the \
17506             accessor's Option::None unchanged",
17507        );
17508    }
17509
17510    // ── Caixa::entrada — outer top-level Option<&Entrada> composite-reference accessor ──
17511
17512    fn caixa_aplicacao_with_entrada(entrada: Option<crate::aplicacao::Entrada>) -> Caixa {
17513        use crate::aplicacao::{Membro, WitContract};
17514        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17515        c.kind = CaixaKind::Aplicacao;
17516        c.membros = vec![Membro {
17517            caixa: "a".into(),
17518            versao: "^0.1".into(),
17519        }];
17520        c.contratos = vec![WitContract {
17521            de: "a".into(),
17522            para: "a".into(),
17523            wit: "wasi:http/proxy".into(),
17524            endpoint: Some("/x".into()),
17525            subject: None,
17526            slot: None,
17527        }];
17528        c.entrada = entrada;
17529        c
17530    }
17531
17532    #[test]
17533    fn entrada_returns_entrada_option_ref_verbatim_across_permutations() {
17534        // The canonical per-`Caixa` `:entrada` M3 mesh-slot outer-
17535        // composite optional-composite-reference-shape pin:
17536        // [`Caixa::entrada`] must return the `:entrada` typed
17537        // `Option<Entrada>` verbatim as an `Option<&Entrada>`
17538        // reference over the same backing storage the raw
17539        // `self.entrada.as_ref()` field access borrows from,
17540        // byte-equal across every representative fixture in the
17541        // accept-set — the author-omitted `None` shape (the
17542        // "cluster-internal Aplicacao" partition every downstream
17543        // Gateway-API emitter treats as "emit no listener + no
17544        // HTTPRoute"), a bare-`host`/`para` minimum-composite fixture
17545        // (empty `paths` — the resolved-paths fallback the peer
17546        // [`crate::aplicacao::Entrada::resolved_paths`] cascade folds
17547        // onto the substrate catch-all), and a fully-populated
17548        // multi-path-with-non-default-port fixture (the canonical
17549        // shape a public HTTP Aplicacao carries).
17550        //
17551        // Pins against a future silent detour that returned a fresh-
17552        // cloned [`crate::aplicacao::Entrada`] copy (which would
17553        // type-check via the `Clone` impl but silently break every
17554        // downstream caller that relied on the reference sharing the
17555        // composite's backing identity), a reference to an operator-
17556        // resolved overlay (the future per-cluster
17557        // `:entrada-overrides` slot — its resolution must land at
17558        // exactly this accessor body, not silently divert the raw
17559        // slot away from the peer [`Caixa::declared_mesh_slots`]
17560        // enumerator's presence probe), or an axis-shuffled projection
17561        // (a future detour that swapped `host` and `para` through the
17562        // accessor would silently split the paired
17563        // [`Caixa::aplicacao_view`] seed's forward input from the
17564        // sibling M3 gateway-artifact emitter's projection input).
17565        //
17566        // Fifth and final outer top-level [`Caixa`]
17567        // `Option<&Composite>`-return composite-reference accessor pin
17568        // on the substrate primitive — peer of the sibling
17569        // `limits_returns_limits_option_ref_verbatim_across_permutations`
17570        // (b2bd9d7),
17571        // `behavior_returns_behavior_option_ref_verbatim_across_permutations`
17572        // (35d8b52),
17573        // `politicas_returns_politicas_option_ref_verbatim_across_permutations`
17574        // (5d23d29), and
17575        // `placement_returns_placement_option_ref_verbatim_across_permutations`
17576        // (4fb8074) opening tetrad pins on the outer top-level
17577        // [`Caixa`] `Option<&Composite>`-return sub-family — extended
17578        // here to the third and final M3 mesh-slot axis so the closed
17579        // outer `Option<&Composite>` sub-family carries the same
17580        // "byte-equal, borrow-shared, presence-bit-preserved" outer-
17581        // accessor discipline across all five arms.
17582        use crate::aplicacao::Entrada;
17583        let fixtures: Vec<Option<Entrada>> = vec![
17584            None,
17585            Some(Entrada {
17586                host: "checkout.quero.cloud".into(),
17587                para: "gateway".into(),
17588                paths: Vec::new(),
17589                port: crate::DEFAULT_SERVICO_PORT,
17590            }),
17591            Some(Entrada {
17592                host: "api.pleme.io".into(),
17593                para: "public-api".into(),
17594                paths: vec!["/v1".into(), "/v2".into()],
17595                port: 8080,
17596            }),
17597        ];
17598        for entrada in fixtures {
17599            let c = caixa_aplicacao_with_entrada(entrada.clone());
17600            assert_eq!(
17601                c.entrada(),
17602                entrada.as_ref(),
17603                "Caixa::entrada must return :entrada verbatim (got \
17604                 {:?}, expected {:?})",
17605                c.entrada(),
17606                entrada.as_ref(),
17607            );
17608            match (c.entrada(), c.entrada.as_ref()) {
17609                (Some(a), Some(b)) => assert!(
17610                    std::ptr::eq(a, b),
17611                    "Caixa::entrada accessor and self.entrada.as_ref() \
17612                     field access must borrow the same backing storage \
17613                     — the accessor is the substrate-primitive typed \
17614                     dispatch every downstream Aplicacao-external- \
17615                     gateway composite consumer must route through, and \
17616                     a reference-identity split would silently break \
17617                     every consumer that relied on the borrow sharing \
17618                     the composite's storage",
17619                ),
17620                (None, None) => {}
17621                _ => panic!(
17622                    "Caixa::entrada presence bit must byte-equal \
17623                     self.entrada.is_some() — a presence-bit drift \
17624                     would silently split the paired \
17625                     Caixa::aplicacao_view Aplicacao-composition seed's \
17626                     traversal head from the peer \
17627                     Caixa::declared_mesh_slots M3 declared-slot \
17628                     enumerator's presence probe",
17629                ),
17630            }
17631            assert_eq!(
17632                c.entrada().is_some(),
17633                c.entrada.is_some(),
17634                "Caixa::entrada().is_some() must byte-equal \
17635                 self.entrada.is_some() — a presence-bit drift would \
17636                 silently split every downstream Option<&Entrada> \
17637                 consumer's partition on the cluster-internal arm",
17638            );
17639        }
17640    }
17641
17642    #[test]
17643    fn declared_mesh_slots_entrada_arm_routes_through_accessor() {
17644        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:entrada`
17645        // presence-probe arm must key off [`Caixa::entrada`], not the
17646        // raw `self.entrada.is_some()` field-probe. Structurally: a
17647        // `Caixa { entrada: Some(Entrada { host: "...", para: "...",
17648        // paths: [], port: DEFAULT_SERVICO_PORT }), .. }` must push
17649        // `M3_AUTHOR_KEY_ENTRADA` onto the declared-slot list (the
17650        // presence bit is `Some`, so the M3 kind-coherence gate must
17651        // surface the slot as "declared" even when every per-axis
17652        // scalar defers to the substrate catch-all / default port),
17653        // and a `Caixa { entrada: None, .. }` must NOT push the label
17654        // (the "author omitted the slot entirely" partition). The pair
17655        // jointly pins the accessor + declared-slot enumerator
17656        // composition: any future silent detour that had the accessor
17657        // collapse `Some(Entrada { paths: [], .. })` to `None` (a
17658        // `.filter(|e| !e.paths.is_empty())` projection) would silently
17659        // absorb the "declared but empty-paths" arm at the accessor
17660        // boundary and the
17661        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
17662        // coherence gate would silently accept a struct-literal
17663        // `Caixa` carrying the drift.
17664        //
17665        // Peer of the sibling
17666        // `declared_servico_slots_limits_arm_routes_through_accessor`
17667        // (b2bd9d7),
17668        // `declared_servico_slots_behavior_arm_routes_through_accessor`
17669        // (35d8b52),
17670        // `declared_mesh_slots_politicas_arm_routes_through_accessor`
17671        // (5d23d29), and
17672        // `declared_mesh_slots_placement_arm_routes_through_accessor`
17673        // (4fb8074) composition pins on the sibling `:limits` /
17674        // `:behavior` / `:politicas` / `:placement` outer-
17675        // `Option<&Composite>` arms — same "the enumerator gate must
17676        // route through the substrate-primitive typed dispatch"
17677        // discipline extended onto the third and final M3 mesh-slot
17678        // axis so the [`Caixa::declared_mesh_slots`] enumerator now
17679        // carries the routing invariant on every M3 mesh-slot arm.
17680        use crate::aplicacao::Entrada;
17681        let c = caixa_aplicacao_with_entrada(Some(Entrada {
17682            host: "checkout.quero.cloud".into(),
17683            para: "gateway".into(),
17684            paths: Vec::new(),
17685            port: crate::DEFAULT_SERVICO_PORT,
17686        }));
17687        let slots = c.declared_mesh_slots();
17688        assert!(
17689            slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
17690            "declared_mesh_slots must push M3_AUTHOR_KEY_ENTRADA when \
17691             `:entrada` is Some (even for empty-paths / default-port) \
17692             — the accessor and the enumerator gate must route through \
17693             the same substrate-primitive typed dispatch on the outer \
17694             :entrada presence bit (got slots={slots:?})",
17695        );
17696        let c = caixa_aplicacao_with_entrada(None);
17697        let slots = c.declared_mesh_slots();
17698        assert!(
17699            !slots.contains(&crate::render::M3_AUTHOR_KEY_ENTRADA),
17700            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_ENTRADA \
17701             when `:entrada` is None — the author-omitted arm must \
17702             route through the accessor's None-return unchanged (got \
17703             slots={slots:?})",
17704        );
17705    }
17706
17707    #[test]
17708    fn aplicacao_view_entrada_arm_folds_through_accessor() {
17709        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:entrada`
17710        // Aplicacao-composition seed must fold through
17711        // [`Caixa::entrada`], not the raw `self.entrada.clone()` field-
17712        // borrow. Structurally: a `Caixa { entrada: Some(Entrada {
17713        // host: "api.pleme.io", para: "public-api", paths: ["/v1"],
17714        // port: 8080 }), kind: Aplicacao, .. }` must surface a projected
17715        // [`crate::AplicacaoSpec`] whose `entrada().unwrap()` byte-
17716        // equals the outer composite's authored value (the fold must
17717        // project the authored composite verbatim), and a `Caixa {
17718        // entrada: None, kind: Aplicacao, .. }` must surface an
17719        // [`crate::AplicacaoSpec`] whose `entrada()` is `None` (the
17720        // "author omitted the slot entirely" arm folds through the
17721        // accessor's `Option::cloned` onto the same `None` presence
17722        // bit — unlike the peer `:politicas` / `:placement` arms
17723        // `:entrada` has no cluster-default fold, the omitted arm
17724        // stays omitted). The pair jointly pins the accessor +
17725        // Aplicacao-composition seed composition: any future silent
17726        // detour that had the accessor divert the raw slot away from
17727        // the seed's fold (an operator-resolved overlay's forward arm
17728        // silently differing from the raw slot's forward arm) would
17729        // silently split the build-time gateway-artifact emission gate
17730        // from the caixa-mesh renderer's Aplicacao-view input at the
17731        // composition boundary.
17732        use crate::aplicacao::Entrada;
17733        let authored = Entrada {
17734            host: "api.pleme.io".into(),
17735            para: "public-api".into(),
17736            paths: vec!["/v1".into()],
17737            port: 8080,
17738        };
17739        let c = caixa_aplicacao_with_entrada(Some(authored.clone()));
17740        let view = c.aplicacao_view().unwrap();
17741        assert_eq!(
17742            view.entrada(),
17743            Some(&authored),
17744            "Caixa::aplicacao_view must fold the authored :entrada \
17745             composite through the accessor verbatim onto the \
17746             projected AplicacaoSpec — a future silent detour at the \
17747             seed's fold arm would surface here as a projected- \
17748             composite drift (got {:?})",
17749            view.entrada(),
17750        );
17751        let c = caixa_aplicacao_with_entrada(None);
17752        let view = c.aplicacao_view().unwrap();
17753        assert!(
17754            view.entrada().is_none(),
17755            "Caixa::aplicacao_view must fold None through the \
17756             accessor's Option::cloned onto None — the author- \
17757             omitted arm must route through the accessor's None-return \
17758             unchanged (got {:?})",
17759            view.entrada(),
17760        );
17761    }
17762
17763    #[test]
17764    fn entrada_projects_option_ref_by_borrow() {
17765        // The by-borrow pin: [`Caixa::entrada`] returns
17766        // `Option<&Entrada>` by borrow — the returned reference
17767        // borrows the underlying `Option<Entrada>` storage of the
17768        // `:entrada` slot and the accessor must not clone the backing
17769        // composite on every call. Peer of the sibling
17770        // `limits_projects_option_ref_by_borrow` (b2bd9d7),
17771        // `behavior_projects_option_ref_by_borrow` (35d8b52),
17772        // `politicas_projects_option_ref_by_borrow` (5d23d29), and
17773        // `placement_projects_option_ref_by_borrow` (4fb8074) by-
17774        // borrow pins on the outer top-level [`Caixa`]
17775        // `Option<&Composite>`-return sub-family — extended here to
17776        // the fifth and final axis of the same sub-family, closing
17777        // the discipline: the accessor's returned reference must
17778        // borrow from `&self` (the returned reference's lifetime is
17779        // tied to `&self`), and calling the accessor twice on the
17780        // same [`Caixa`] must yield references that are pointer-equal
17781        // (the underlying byte-buffer is the storage `Entrada`'s
17782        // allocation, not a fresh copy) as well as value-equal
17783        // (idempotent, no side effects on `&self`).
17784        //
17785        // Pins against a future silent detour that returned an owned
17786        // `Entrada` (which would type-check via the `Clone` impl but
17787        // silently clone on every call), a `&Entrada` panic-return on
17788        // the `None` arm (which would collapse the load-bearing
17789        // `Option` presence-bit into a runtime panic), or a one-arm-
17790        // only accessor that returned a saturating composite on some
17791        // sentinel input.
17792        use crate::aplicacao::Entrada;
17793        for entrada in [
17794            Some(Entrada {
17795                host: "checkout.quero.cloud".into(),
17796                para: "gateway".into(),
17797                paths: Vec::new(),
17798                port: crate::DEFAULT_SERVICO_PORT,
17799            }),
17800            Some(Entrada {
17801                host: "api.pleme.io".into(),
17802                para: "public-api".into(),
17803                paths: vec!["/v1".into(), "/v2".into()],
17804                port: 8080,
17805            }),
17806        ] {
17807            let c = caixa_aplicacao_with_entrada(entrada.clone());
17808            let first = c.entrada().unwrap();
17809            let second = c.entrada().unwrap();
17810            assert_eq!(
17811                first, second,
17812                "Caixa::entrada must be idempotent — two successive \
17813                 calls on the same &self must return the same &Entrada",
17814            );
17815            assert!(
17816                std::ptr::eq(first, second),
17817                "Caixa::entrada must borrow the underlying \
17818                 Option<Entrada> storage — two successive calls must \
17819                 return references with the same backing pointer (a \
17820                 fresh Entrada clone would change the pointer on every \
17821                 call)",
17822            );
17823            assert_eq!(
17824                Some(first),
17825                entrada.as_ref(),
17826                "Caixa::entrada must return :entrada verbatim by \
17827                 borrow — got {first:?}, expected {:?}",
17828                entrada.as_ref(),
17829            );
17830        }
17831        let c = caixa_aplicacao_with_entrada(None);
17832        assert!(
17833            c.entrada().is_none(),
17834            "Caixa::entrada must return None when :entrada is absent \
17835             — the author-omitted arm must project through the \
17836             accessor's Option::None unchanged",
17837        );
17838    }
17839
17840    // ── Caixa::estrategia — outer top-level Option<RestartStrategy> flat-spread supervisor-tree accessor ──
17841
17842    fn caixa_with_estrategia(estrategia: Option<crate::supervisor::RestartStrategy>) -> Caixa {
17843        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
17844        c.estrategia = estrategia;
17845        c
17846    }
17847
17848    #[test]
17849    fn estrategia_returns_estrategia_option_verbatim_across_permutations() {
17850        // The canonical per-`Caixa` `:estrategia` M2 supervisor-tree-slot
17851        // flat-spread `Option<RestartStrategy>`-return `Copy`-composite-
17852        // enum-arm scalar shape pin: [`Caixa::estrategia`] must return
17853        // the `:estrategia` typed `Option<crate::supervisor::RestartStrategy>`
17854        // verbatim as an `Option<RestartStrategy>` `Copy`-projected value
17855        // over the same discriminant the raw `self.estrategia` field
17856        // access carries, byte-equal across every representative fixture
17857        // in the accept-set — the author-omitted `None` shape (the
17858        // "defer to [`RestartStrategy::default`] through the
17859        // [`Self::supervisor_view`] `unwrap_or_default()` fold" partition
17860        // every non-`Supervisor`-kind `defcaixa` carries by
17861        // `#[serde(default)]`), and each of the four closed-set variants
17862        // [`RestartStrategy::OneForOne`] / [`RestartStrategy::OneForAll`]
17863        // / [`RestartStrategy::RestForOne`] /
17864        // [`RestartStrategy::SimpleOneForOne`] the author-declared arm
17865        // partitions on.
17866        //
17867        // Pins against a future silent detour that re-derived the
17868        // strategy from a peer axis (an accidental fallback to
17869        // `if children.is_empty() { SimpleOneForOne } else { OneForOne }`
17870        // collapse that read the outer `:children` list-length axis into
17871        // the strategy discriminator at the accessor boundary), a
17872        // stale-derive detour that substituted [`RestartStrategy::default`]
17873        // when the outer `Option` held `None` (which would silently
17874        // collapse the load-bearing "author explicitly declared
17875        // `:estrategia OneForOne`" vs "author omitted the slot and
17876        // inherited the default" partition the [`Self::declared_supervisor_slots`]
17877        // presence-probe reads — the enumerator gate would still push
17878        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` on the omitted arm, silently
17879        // splitting the paired [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
17880        // kind-coherence gate's traversal head from the
17881        // [`Self::supervisor_view`] `unwrap_or_default()` fold's
17882        // composition head), a reference to an operator-resolved overlay
17883        // (the future per-cluster `:estrategia-overrides` slot — its
17884        // resolution must land at exactly this accessor body, not
17885        // silently divert the raw slot away from a second consumer), or
17886        // an axis-remap projection (a future detour that mapped
17887        // `OneForAll` through the accessor onto `OneForOne` would
17888        // silently split every downstream sibling-restart-strategy
17889        // consumer's per-arm fan-out).
17890        //
17891        // First outer top-level [`Caixa`] `Option<Copy>`-return
17892        // supervisor-tree-slot flat-spread accessor pin on the substrate
17893        // primitive — opens the outer-`Caixa` `Option<Copy>` flat-spread
17894        // projection pattern the sibling per-`Caixa` `:max-restarts` /
17895        // `:restart-window` future outer-scalar pins fold on. Peer of
17896        // the inner-altitude
17897        // `supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
17898        // (eafb619) pin on the post-composition [`SupervisorSpec`]
17899        // altitude — same "the substrate-primitive accessor must byte-
17900        // equal the raw field access verbatim across every author-
17901        // declared value" discipline extended onto the pre-composition
17902        // outer author-surface [`Caixa`] altitude. Peer of the closed
17903        // outer-`Caixa` `Option<&Composite>` composite-reference family
17904        // the sibling `limits` / `behavior` / `politicas` / `placement` /
17905        // `entrada`
17906        // `..._returns_..._option_ref_verbatim_across_permutations` pins
17907        // already carry on the outer `Option<&Composite>` altitude.
17908        use crate::supervisor::RestartStrategy;
17909        let fixtures: Vec<Option<RestartStrategy>> = vec![
17910            None,
17911            Some(RestartStrategy::OneForOne),
17912            Some(RestartStrategy::OneForAll),
17913            Some(RestartStrategy::RestForOne),
17914            Some(RestartStrategy::SimpleOneForOne),
17915        ];
17916        for estrategia in fixtures {
17917            let c = caixa_with_estrategia(estrategia);
17918            assert_eq!(
17919                c.estrategia(),
17920                estrategia,
17921                "Caixa::estrategia must return :estrategia verbatim (got \
17922                 {:?}, expected {:?})",
17923                c.estrategia(),
17924                estrategia,
17925            );
17926            assert_eq!(
17927                c.estrategia(),
17928                c.estrategia,
17929                "Caixa::estrategia accessor and self.estrategia field \
17930                 access must byte-equal — the accessor is the substrate-\
17931                 primitive typed dispatch every downstream supervisor-\
17932                 tree flat-spread consumer must route through, and a \
17933                 discriminant split would silently break every consumer \
17934                 that relied on the accessor sharing the field's own \
17935                 Option<Copy> shape",
17936            );
17937            assert_eq!(
17938                c.estrategia().is_some(),
17939                c.estrategia.is_some(),
17940                "Caixa::estrategia().is_some() must byte-equal \
17941                 self.estrategia.is_some() — a presence-bit drift would \
17942                 silently split the paired Caixa::declared_supervisor_slots \
17943                 presence-probe arm from the Caixa::supervisor_view \
17944                 unwrap_or_default() fold's composition input",
17945            );
17946        }
17947    }
17948
17949    #[test]
17950    fn declared_supervisor_slots_estrategia_arm_routes_through_accessor() {
17951        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
17952        // `:estrategia` presence-probe arm must key off
17953        // [`Caixa::estrategia`], not the raw `self.estrategia.is_some()`
17954        // field-probe. Structurally: every `Caixa { estrategia:
17955        // Some(RestartStrategy::_), .. }` variant must push
17956        // `SUPERVISOR_AUTHOR_KEY_ESTRATEGIA` onto the declared-slot list
17957        // (the presence bit is `Some` for every closed-set variant, so
17958        // the M2 supervisor-tree kind-coherence gate must surface the
17959        // slot as "declared" regardless of which variant the author
17960        // picked), and a `Caixa { estrategia: None, .. }` must NOT push
17961        // the label (the "author omitted the slot entirely, deferring
17962        // to [`RestartStrategy::default`] through the supervisor_view
17963        // fold" partition). The pair jointly pins the accessor +
17964        // declared-slot enumerator composition: any future silent detour
17965        // that had the accessor collapse `Some(RestartStrategy::default())`
17966        // to `None` (a `.filter(|e| *e != RestartStrategy::default())`
17967        // projection) would silently absorb the "declared but default-
17968        // valued" arm at the accessor boundary and the
17969        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`] kind-
17970        // coherence gate would silently accept a struct-literal `Caixa`
17971        // carrying the drift.
17972        //
17973        // Peer of the sibling per-`Caixa`
17974        // `declared_servico_slots_limits_arm_routes_through_accessor`
17975        // (b2bd9d7) accessor-composition pin on the sibling outer-`Caixa`
17976        // `Option<&LimitsSpec>` composition axis — same "the enumerator
17977        // gate must route through the substrate-primitive typed
17978        // dispatch" discipline extended onto the flat-spread M2
17979        // supervisor-tree `Option<RestartStrategy>`-composition surface,
17980        // opening the outer-`Caixa` supervisor-tree-slot arm of the
17981        // composition-pin family.
17982        use crate::supervisor::RestartStrategy;
17983        for estrategia in [
17984            RestartStrategy::OneForOne,
17985            RestartStrategy::OneForAll,
17986            RestartStrategy::RestForOne,
17987            RestartStrategy::SimpleOneForOne,
17988        ] {
17989            let c = caixa_with_estrategia(Some(estrategia));
17990            let slots = c.declared_supervisor_slots();
17991            assert!(
17992                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
17993                "declared_supervisor_slots must push \
17994                 SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is \
17995                 Some({estrategia:?}) — the accessor and the enumerator \
17996                 gate must route through the same substrate-primitive \
17997                 typed dispatch on the outer :estrategia presence bit \
17998                 (got slots={slots:?})",
17999            );
18000        }
18001        let c = caixa_with_estrategia(None);
18002        let slots = c.declared_supervisor_slots();
18003        assert!(
18004            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_ESTRATEGIA),
18005            "declared_supervisor_slots must NOT push \
18006             SUPERVISOR_AUTHOR_KEY_ESTRATEGIA when `:estrategia` is None \
18007             — the author-omitted arm must route through the accessor's \
18008             None-return unchanged (got slots={slots:?})",
18009        );
18010    }
18011
18012    #[test]
18013    fn supervisor_view_estrategia_arm_routes_through_accessor() {
18014        // Composition pin: [`Caixa::supervisor_view`]'s per-`:estrategia`
18015        // [`SupervisorSpec`] construction arm must key off
18016        // [`Caixa::estrategia`]'s `unwrap_or_default()` fold, not the raw
18017        // `self.estrategia.unwrap_or_default()` field-fold. Structurally:
18018        // for every `:kind Supervisor` `Caixa` carrying an author-
18019        // declared `Some(RestartStrategy::_)` variant, the composed
18020        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal the
18021        // outer accessor's declared variant unchanged; and for a
18022        // `:kind Supervisor` `Caixa` carrying `None`, the composed
18023        // [`SupervisorSpec`]'s `.estrategia` field must byte-equal
18024        // [`RestartStrategy::default`] (the [`RestartStrategy::OneForOne`]
18025        // arm the flat-spread `unwrap_or_default()` fold projects to on
18026        // the author-omitted arm — this is the *composition* between the
18027        // outer `Option<RestartStrategy>` accessor's presence-bit
18028        // surface and the inner post-composition non-`Option`
18029        // [`SupervisorSpec::estrategia`] altitude). The pair jointly
18030        // pins the accessor + supervisor_view composition: any future
18031        // silent detour that had the accessor promote `None` to
18032        // `Some(RestartStrategy::default())` (a `.or_else(|| Some(RestartStrategy::default()))`
18033        // projection) would silently collapse the two arms into one at
18034        // the accessor boundary and the [`Self::declared_supervisor_slots`]
18035        // presence probe would silently drift from the composition site.
18036        //
18037        // Peer of the sibling M2 supervisor-slot post-composition
18038        // `validate_reads_through_lifted_estrategia_accessor` (eafb619)
18039        // pin on the [`SupervisorSpec::validate`] altitude — this pin
18040        // extends that inner-altitude accessor-routing discipline onto
18041        // the pre-composition outer author-surface [`Caixa`] altitude,
18042        // pinning the composition edge between the flat-spread outer
18043        // `Option<RestartStrategy>` and the composed [`SupervisorSpec`]
18044        // `RestartStrategy` axes.
18045        use crate::CaixaKind;
18046        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
18047        for estrategia in [
18048            RestartStrategy::OneForOne,
18049            RestartStrategy::OneForAll,
18050            RestartStrategy::RestForOne,
18051            RestartStrategy::SimpleOneForOne,
18052        ] {
18053            let mut c = caixa_with_estrategia(Some(estrategia));
18054            c.kind = CaixaKind::Supervisor;
18055            // Route the `SimpleOneForOne ↔ non-SimpleOneForOne` fixture-
18056            // shape partition through the [`gen_platform::IsVariant`]
18057            // derive-generated
18058            // [`RestartStrategy::is_simple_one_for_one`] predicate rather
18059            // than the raw `matches!(estrategia, RestartStrategy::
18060            // SimpleOneForOne)` open-coded pattern-match — same closed-
18061            // set-typed-enum arm-discriminator dispatch discipline the
18062            // sibling [`crate::upgrade::UpgradeInstruction::is_restart`]
18063            // convergence (915a934) extended onto its two paired positive
18064            // / negated `matches!` sites and the peer
18065            // [`crate::aplicacao::PlacementStrategy`] `IsVariant`-derived
18066            // predicate convergence (766ec63) extended onto the M3 mesh-
18067            // slot per-`:placement` distribution-strategy discriminator
18068            // axis. See the sibling `supervisor::tests::
18069            // round_trip_all_strategies` and
18070            // `supervisor::tests::supervisor_spec_estrategia_returns_estrategia_verbatim_across_permutations`
18071            // fixtures — the three sites (all test-only,
18072            // acknowledged in 915a934's Prior-commits footnote as the
18073            // outstanding follow-up) now consult one typed dispatch on
18074            // the substrate primitive.
18075            c.children = if estrategia.is_simple_one_for_one() {
18076                Vec::new()
18077            } else {
18078                vec![ChildSpec {
18079                    caixa: "worker".into(),
18080                    versao: "^0.1".into(),
18081                    restart: RestartPolicy::Permanent,
18082                }]
18083            };
18084            let view = c.supervisor_view().expect(
18085                "supervisor_view must materialize a SupervisorSpec for a \
18086                 :kind Supervisor Caixa carrying a Some(:estrategia) slot",
18087            );
18088            assert_eq!(
18089                view.estrategia(),
18090                c.estrategia().unwrap(),
18091                "supervisor_view must carry the outer Caixa::estrategia() \
18092                 declared variant onto the composed SupervisorSpec.estrategia \
18093                 field verbatim on the Some arm (got {:?}, expected {:?})",
18094                view.estrategia(),
18095                c.estrategia().unwrap(),
18096            );
18097        }
18098        // The author-omitted arm: outer `None` → composed
18099        // `RestartStrategy::default()` through the flat-spread
18100        // `unwrap_or_default()` fold.
18101        let mut c = caixa_with_estrategia(None);
18102        c.kind = CaixaKind::Supervisor;
18103        // Populate children so the sibling supervisor slots are coherent
18104        // for the [`Self::supervisor_view`] projection; the `:estrategia`
18105        // arm still defers to [`RestartStrategy::default`] on the
18106        // author-omitted arm even when the sibling slots carry values.
18107        c.children = vec![ChildSpec {
18108            caixa: "worker".into(),
18109            versao: "^0.1".into(),
18110            restart: RestartPolicy::Permanent,
18111        }];
18112        let view = c.supervisor_view().expect(
18113            "supervisor_view must materialize a SupervisorSpec for a \
18114             :kind Supervisor Caixa carrying a None `:estrategia` slot",
18115        );
18116        assert_eq!(
18117            view.estrategia(),
18118            RestartStrategy::default(),
18119            "supervisor_view must project the outer Caixa::estrategia() \
18120             None arm onto RestartStrategy::default() through the flat-\
18121             spread unwrap_or_default() fold (got {:?}, expected {:?})",
18122            view.estrategia(),
18123            RestartStrategy::default(),
18124        );
18125        assert!(
18126            c.estrategia().is_none(),
18127            "Caixa::estrategia() must remain None on the author-omitted \
18128             arm — the supervisor_view fold must not mutate the outer \
18129             flat-spread presence bit",
18130        );
18131    }
18132
18133    #[test]
18134    fn estrategia_projects_option_by_copy() {
18135        // The by-`Copy` pin: [`Caixa::estrategia`] returns
18136        // `Option<RestartStrategy>` by value (`RestartStrategy: Copy`) —
18137        // the accessor does not borrow `&self` past the call (no
18138        // lifetime on the return type), and calling the accessor twice
18139        // on the same [`Caixa`] must yield discriminant-equal values
18140        // (idempotent, no side effects on `&self`). Peer of the sibling
18141        // outer-`Caixa` `Option<&Composite>` by-borrow
18142        // `limits_projects_option_ref_by_borrow` (b2bd9d7) /
18143        // `behavior_projects_option_ref_by_borrow` (35d8b52) /
18144        // `politicas_projects_option_ref_by_borrow` (5d23d29) /
18145        // `placement_projects_option_ref_by_borrow` (4fb8074) /
18146        // `entrada_projects_option_ref_by_borrow` (e4128e4) by-borrow
18147        // pins on the outer-`Caixa` `Option<&Composite>`-return axes —
18148        // extended here to the outer-`Caixa` `Option<Copy>`-return
18149        // flat-spread axis. The `Copy` discipline replaces the pointer-
18150        // equality claim the by-borrow siblings pin (a fresh `Copy` of a
18151        // `Copy` discriminant is definitionally the same discriminant, so
18152        // the axis reduces to discriminant equality).
18153        //
18154        // Pins against a future silent detour that returned a fresh
18155        // `Option<&RestartStrategy>` (which would type-check but silently
18156        // introduce a borrow of `&self` past the call, collapsing the
18157        // load-bearing "no lifetime on the return type" `Copy` projection
18158        // the flat-spread axis's `Option<Copy>` shape carries), a stale-
18159        // read side effect that flipped the outer discriminant on
18160        // successive calls, or an axis-remap projection that returned a
18161        // different variant than the field storage.
18162        use crate::supervisor::RestartStrategy;
18163        for estrategia in [
18164            Some(RestartStrategy::OneForOne),
18165            Some(RestartStrategy::OneForAll),
18166            Some(RestartStrategy::RestForOne),
18167            Some(RestartStrategy::SimpleOneForOne),
18168        ] {
18169            let c = caixa_with_estrategia(estrategia);
18170            let first = c.estrategia();
18171            let second = c.estrategia();
18172            assert_eq!(
18173                first, second,
18174                "Caixa::estrategia must be idempotent — two successive \
18175                 calls on the same &self must return the same \
18176                 Option<RestartStrategy>",
18177            );
18178            assert_eq!(
18179                first, estrategia,
18180                "Caixa::estrategia must return :estrategia verbatim by \
18181                 Copy — got {first:?}, expected {estrategia:?}",
18182            );
18183        }
18184        let c = caixa_with_estrategia(None);
18185        assert!(
18186            c.estrategia().is_none(),
18187            "Caixa::estrategia must return None when :estrategia is \
18188             absent — the author-omitted arm must project through the \
18189             accessor's Option::None unchanged",
18190        );
18191    }
18192
18193    // ── Caixa::max_restarts / Caixa::restart_window —
18194    //    outer top-level M2 supervisor-tree-slot flat-spread accessors
18195    //    (Option<u32> / Option<&str>) folding on the ed04d3c
18196    //    Caixa::estrategia Option<Copy> sub-family ─────────────────────
18197
18198    fn caixa_with_max_restarts(max_restarts: Option<u32>) -> Caixa {
18199        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18200        c.max_restarts = max_restarts;
18201        c
18202    }
18203
18204    fn caixa_supervisor_with_max_restarts_and_window(
18205        max_restarts: Option<u32>,
18206        restart_window: Option<&str>,
18207    ) -> Caixa {
18208        use crate::CaixaKind;
18209        use crate::supervisor::{ChildSpec, RestartPolicy};
18210        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
18211        c.kind = CaixaKind::Supervisor;
18212        c.max_restarts = max_restarts;
18213        c.restart_window = restart_window.map(str::to_string);
18214        c.children = vec![ChildSpec {
18215            caixa: "worker".into(),
18216            versao: "^0.1".into(),
18217            restart: RestartPolicy::Permanent,
18218        }];
18219        c
18220    }
18221
18222    #[test]
18223    fn max_restarts_returns_max_restarts_option_verbatim_across_permutations() {
18224        // Value-shape pin: [`Caixa::max_restarts`] returns the
18225        // `:max-restarts` typed `Option<u32>` verbatim, `Copy`-projected
18226        // from the typed slot's own storage, byte-equal across the
18227        // author-omitted `None` arm (the "defer to the
18228        // [`Self::supervisor_view`] `unwrap_or(5)` OTP-canonical
18229        // `{intensity, 5, 60}` default" partition every
18230        // non-`Supervisor`-kind caixa carries by `#[serde(default)]`)
18231        // and each of the representative fixtures in the accept-set —
18232        // `0` (the zero-floor arm the peer
18233        // [`crate::supervisor::SupervisorSpec::validate`]
18234        // [`crate::SupervisorError::ZeroMaxRestarts`] gate refuses on
18235        // the post-composition altitude — the accessor must ship the
18236        // raw slot verbatim so struct-literal fixtures continue to
18237        // expose the zero at the accessor boundary), the OTP-canonical
18238        // `5` default (`{intensity, 5, 60}` worker-supervisor from
18239        // Learn You Some Erlang), `1000` (the
18240        // [`SUPERVISOR_MAX_RESTARTS_MAX`] cap the peer post-composition
18241        // upper-bound gate accepts on the boundary), `u32::MAX` (a
18242        // past-the-cap sentinel that the substrate-primitive accessor
18243        // must still ship verbatim). Second outer top-level
18244        // [`Caixa`] `Option<Copy>`-return supervisor-tree flat-spread
18245        // pin — folds on the sibling
18246        // `estrategia_returns_estrategia_option_verbatim_across_permutations`
18247        // (ed04d3c) pin's `Option<Copy>` shape, extending the sub-family
18248        // onto the sibling `Option<u32>` restart-budget-count arm.
18249        let fixtures: Vec<Option<u32>> = vec![None, Some(0), Some(5), Some(1000), Some(u32::MAX)];
18250        for max_restarts in fixtures {
18251            let c = caixa_with_max_restarts(max_restarts);
18252            assert_eq!(
18253                c.max_restarts(),
18254                max_restarts,
18255                "Caixa::max_restarts must return :max-restarts verbatim \
18256                 (got {:?}, expected {max_restarts:?})",
18257                c.max_restarts(),
18258            );
18259            assert_eq!(
18260                c.max_restarts(),
18261                c.max_restarts,
18262                "Caixa::max_restarts accessor and self.max_restarts \
18263                 field access must byte-equal — a presence-bit or count \
18264                 drift would silently split the paired \
18265                 Caixa::declared_supervisor_slots presence-probe arm \
18266                 from the Caixa::supervisor_view unwrap_or(5) fold's \
18267                 composition input",
18268            );
18269        }
18270    }
18271
18272    #[test]
18273    fn max_restarts_projects_option_by_copy() {
18274        // The by-`Copy` pin: [`Caixa::max_restarts`] returns
18275        // `Option<u32>` by value (`u32: Copy`) — the accessor does not
18276        // borrow `&self` past the call (no lifetime on the return type),
18277        // and calling the accessor twice on the same [`Caixa`] must
18278        // yield equal values (idempotent, no side effects). Peer of the
18279        // sibling `estrategia_projects_option_by_copy` (ed04d3c) pin on
18280        // the outer-`Caixa` `Option<Copy>`-return flat-spread axis.
18281        for max_restarts in [Some(0u32), Some(5), Some(1000), Some(u32::MAX), None] {
18282            let c = caixa_with_max_restarts(max_restarts);
18283            let first = c.max_restarts();
18284            let second = c.max_restarts();
18285            assert_eq!(
18286                first, second,
18287                "Caixa::max_restarts must be idempotent — two successive \
18288                 calls on the same &self must return the same Option<u32>",
18289            );
18290            assert_eq!(
18291                first, max_restarts,
18292                "Caixa::max_restarts must return :max-restarts verbatim \
18293                 by Copy — got {first:?}, expected {max_restarts:?}",
18294            );
18295        }
18296    }
18297
18298    #[test]
18299    fn declared_supervisor_slots_max_restarts_arm_routes_through_accessor() {
18300        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
18301        // `:max-restarts` presence-probe arm must key off
18302        // [`Caixa::max_restarts`], not the raw
18303        // `self.max_restarts.is_some()` field-probe. Structurally: every
18304        // `Caixa { max_restarts: Some(_), .. }` variant must push
18305        // `SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS` onto the declared-slot
18306        // list (the presence bit is `Some` for every representative
18307        // count, so the M2 kind-coherence gate must surface the slot as
18308        // "declared"), and a `Caixa { max_restarts: None, .. }` must
18309        // NOT push the label. Peer of the sibling
18310        // `declared_supervisor_slots_estrategia_arm_routes_through_accessor`
18311        // (ed04d3c) composition pin — same routing-through-accessor
18312        // discipline extended onto the sibling flat-spread `Option<u32>`
18313        // arm.
18314        for max_restarts in [0u32, 5, 1000, u32::MAX] {
18315            let c = caixa_with_max_restarts(Some(max_restarts));
18316            let slots = c.declared_supervisor_slots();
18317            assert!(
18318                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
18319                "declared_supervisor_slots must push \
18320                 SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` \
18321                 is Some({max_restarts}) — the accessor and the \
18322                 enumerator gate must route through the same \
18323                 substrate-primitive typed dispatch on the outer \
18324                 :max-restarts presence bit (got slots={slots:?})",
18325            );
18326        }
18327        let c = caixa_with_max_restarts(None);
18328        let slots = c.declared_supervisor_slots();
18329        assert!(
18330            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS),
18331            "declared_supervisor_slots must NOT push \
18332             SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS when `:max-restarts` is \
18333             None — the author-omitted arm must route through the \
18334             accessor's None-return unchanged (got slots={slots:?})",
18335        );
18336    }
18337
18338    #[test]
18339    fn supervisor_view_max_restarts_arm_routes_through_accessor() {
18340        // Composition pin: [`Caixa::supervisor_view`]'s per-`:max-restarts`
18341        // [`SupervisorSpec`] construction arm must key off
18342        // [`Caixa::max_restarts`]'s `unwrap_or(5)` fold, not the raw
18343        // `self.max_restarts.unwrap_or(5)` field-fold. Structurally: for
18344        // every `:kind Supervisor` `Caixa` carrying an author-declared
18345        // `Some(n)`, the composed [`SupervisorSpec`]'s `.max_restarts()`
18346        // must byte-equal `n`; and for a `:kind Supervisor` `Caixa`
18347        // carrying `None`, the composed [`SupervisorSpec`]'s
18348        // `.max_restarts()` must byte-equal the OTP-canonical `5`. Peer
18349        // of the sibling
18350        // `supervisor_view_estrategia_arm_routes_through_accessor`
18351        // (ed04d3c) composition pin.
18352        for max_restarts in [1u32, 5, 1000] {
18353            let c = caixa_supervisor_with_max_restarts_and_window(Some(max_restarts), None);
18354            let view = c.supervisor_view().expect(
18355                "supervisor_view must materialize a SupervisorSpec for a \
18356                 :kind Supervisor Caixa carrying a Some(:max-restarts)",
18357            );
18358            assert_eq!(
18359                view.max_restarts(),
18360                max_restarts,
18361                "supervisor_view must carry the outer \
18362                 Caixa::max_restarts() Some arm onto the composed \
18363                 SupervisorSpec.max_restarts field verbatim (got {}, \
18364                 expected {max_restarts})",
18365                view.max_restarts(),
18366            );
18367        }
18368        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18369        let view = c.supervisor_view().expect(
18370            "supervisor_view must materialize a SupervisorSpec for a \
18371             :kind Supervisor Caixa carrying a None :max-restarts",
18372        );
18373        assert_eq!(
18374            view.max_restarts(),
18375            5,
18376            "supervisor_view must project the outer \
18377             Caixa::max_restarts() None arm onto the OTP-canonical \
18378             {{intensity, 5, 60}} default (5) through the flat-spread \
18379             unwrap_or(5) fold (got {})",
18380            view.max_restarts(),
18381        );
18382        assert!(
18383            c.max_restarts().is_none(),
18384            "Caixa::max_restarts() must remain None on the author-\
18385             omitted arm — the supervisor_view fold must not mutate \
18386             the outer flat-spread presence bit",
18387        );
18388    }
18389
18390    #[test]
18391    fn supervisor_view_estrategia_fallback_routes_through_lifted_default() {
18392        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
18393        // `:estrategia` arm must degrade onto the substrate-canonical
18394        // [`crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT`] typed
18395        // `pub const` — the Erlang/OTP-canonical `one_for_one` strategy
18396        // half of Learn You Some Erlang's `{one_for_one, intensity, 5, 60}`
18397        // worker-supervisor default — rather than the transitively-
18398        // derived [`crate::supervisor::RestartStrategy::default`] route
18399        // the prior `.unwrap_or_default()` fold reached for. Prior to the
18400        // lift the composition site carried `.unwrap_or_default()` with
18401        // no compile-time link back to the shared OTP-canonical strategy
18402        // default that the paired [`crate::supervisor::Default for
18403        // RestartStrategy`] impl and the [`crate::supervisor::Default for
18404        // SupervisorSpec`] impl's struct-literal `estrategia` field both
18405        // (now) route through the same lifted constant — so a future
18406        // rebrand of the OTP-canonical strategy default (an OTP
18407        // `rest_for_one` widening once the substrate discovers startup-
18408        // order-coupled child cohorts as the more common worker-
18409        // supervisor shape, a per-cluster overlay the operator pins
18410        // through the MESH-COMPOSITION §III.2 supervision-canary
18411        // `:estrategia-overrides` roadmap slot) would have had to migrate
18412        // the paired `MaxIntensity` + `Period` halves through the lifted
18413        // constants and the `one_for_one` half through a
18414        // `RestartStrategy::default()` route in lockstep or a
18415        // `:kind Supervisor` caixa carrying an author-omitted
18416        // `:estrategia` slot would silently resolve to a `SupervisorSpec`
18417        // whose `estrategia` disagreed with the paired
18418        // `SupervisorSpec::default()` view. Byte-parity against the
18419        // lifted constant closes the split. Peer of the sibling
18420        // [`supervisor_view_max_restarts_fallback_routes_through_lifted_default`]
18421        // composition pin on the paired `MaxIntensity` half + the
18422        // [`crate::supervisor::restart_strategy_default_routes_through_lifted_default`]
18423        // + [`crate::supervisor::supervisor_spec_default_estrategia_routes_through_lifted_default`]
18424        // pins on the sibling entry points onto the shared substrate
18425        // constant.
18426        use crate::CaixaKind;
18427        use crate::supervisor::{ChildSpec, RestartPolicy};
18428        let mut c = Caixa::from_lisp(&Caixa::template("root")).unwrap();
18429        c.kind = CaixaKind::Supervisor;
18430        c.estrategia = None;
18431        c.children = vec![ChildSpec {
18432            caixa: "worker".into(),
18433            versao: "^0.1".into(),
18434            restart: RestartPolicy::Permanent,
18435        }];
18436        let view = c.supervisor_view().expect(
18437            "supervisor_view must materialize a SupervisorSpec for a \
18438             :kind Supervisor Caixa carrying a None :estrategia",
18439        );
18440        assert_eq!(
18441            view.estrategia(),
18442            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
18443            "supervisor_view must degrade the outer \
18444             Caixa::estrategia() None arm onto the lifted \
18445             SUPERVISOR_ESTRATEGIA_DEFAULT typed pub const (got {:?}, \
18446             expected {:?})",
18447            view.estrategia(),
18448            crate::supervisor::SUPERVISOR_ESTRATEGIA_DEFAULT,
18449        );
18450    }
18451
18452    #[test]
18453    fn supervisor_view_max_restarts_fallback_routes_through_lifted_default() {
18454        // Composition pin: [`Caixa::supervisor_view`]'s author-omitted
18455        // `:max-restarts` arm must degrade onto the substrate-canonical
18456        // [`crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT`] typed
18457        // `pub const` — the Erlang/OTP-canonical `{intensity, 5, 60}`
18458        // `MaxIntensity` default — rather than a raw `5` literal. Prior
18459        // to the lift the composition site carried an inline
18460        // `.unwrap_or(5)` with no compile-time link back to the shared
18461        // OTP-canonical default that the serde-side
18462        // `#[serde(default = "default_max_restarts")]` wire-format arm
18463        // and the [`Default for crate::supervisor::SupervisorSpec`]
18464        // struct-literal default arm both key off — so a future rebrand
18465        // of the OTP-canonical default (Elixir's `Supervisor` `3`
18466        // default, a per-cluster overlay the operator pins through the
18467        // MESH-COMPOSITION §III.2 supervision-canary
18468        // `:supervisor :max-restarts-overrides` roadmap slot) would
18469        // have had to be threaded through both the serde-side helper
18470        // and this view-construction arm in lockstep or a `:kind
18471        // Supervisor` caixa carrying `:max-restarts ()` would silently
18472        // resolve to a `SupervisorSpec` whose `max_restarts` disagreed
18473        // with the same fixture's serde-side `SupervisorSpec` view (an
18474        // author-omitted slot round-tripping through
18475        // `SupervisorSpec::default()` to the lifted constant, then
18476        // splitting to a stale literal past `supervisor_view`).
18477        // Byte-parity against the lifted constant closes the split.
18478        // Peer of the sibling
18479        // [`crate::supervisor::default_max_restarts_helper_routes_through_lifted_default`]
18480        // + [`crate::supervisor::supervisor_spec_default_max_restarts_routes_through_lifted_default`]
18481        // composition pins that close the same routing on the two
18482        // sibling entry points onto the shared substrate constant.
18483        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18484        let view = c.supervisor_view().expect(
18485            "supervisor_view must materialize a SupervisorSpec for a \
18486             :kind Supervisor Caixa carrying a None :max-restarts",
18487        );
18488        assert_eq!(
18489            view.max_restarts(),
18490            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
18491            "supervisor_view must degrade the outer \
18492             Caixa::max_restarts() None arm onto the lifted \
18493             SUPERVISOR_MAX_RESTARTS_DEFAULT typed pub const (got {}, \
18494             expected {})",
18495            view.max_restarts(),
18496            crate::supervisor::SUPERVISOR_MAX_RESTARTS_DEFAULT,
18497        );
18498    }
18499
18500    #[test]
18501    fn restart_window_returns_restart_window_option_verbatim_across_permutations() {
18502        // Value-shape pin: [`Caixa::restart_window`] returns the
18503        // `:restart-window` typed `Option<String>` verbatim as an
18504        // `Option<&str>`, borrowed from the typed slot's own storage,
18505        // byte-equal across the author-omitted `None` arm and each of
18506        // the representative fixtures in the accept-set — the canonical
18507        // `"60s"` from `{intensity, 5, 60}`, the sibling
18508        // canonical-magnitude forms (`"5m"` / `"1h"` / `"500ms"` / `"30"`
18509        // / `"0s"`) the shared codec's positive-set sweep pin covers,
18510        // plus a past-the-guard sentinel (`"1.5s"` — the fractional-
18511        // seconds drift the sibling [`Self::validate_restart_window`]
18512        // gate refuses; the accessor must ship the raw slot verbatim
18513        // so struct-literal fixtures continue to expose the drift at
18514        // the accessor boundary). Third outer top-level [`Caixa`]
18515        // supervisor-tree flat-spread pin — extends the sub-family onto
18516        // the sibling `Option<&str>` raw-duration-string arm.
18517        for window in [
18518            None,
18519            Some("60s"),
18520            Some("5m"),
18521            Some("1h"),
18522            Some("500ms"),
18523            Some("1.5s"),
18524            Some(""),
18525        ] {
18526            let c = caixa_with_restart_window(window);
18527            assert_eq!(
18528                c.restart_window(),
18529                window,
18530                "Caixa::restart_window must return :restart-window \
18531                 verbatim as Option<&str> (got {:?}, expected {window:?})",
18532                c.restart_window(),
18533            );
18534            assert_eq!(
18535                c.restart_window(),
18536                c.restart_window.as_deref(),
18537                "Caixa::restart_window accessor and \
18538                 self.restart_window.as_deref() field access must \
18539                 byte-equal — a byte-level drift would silently split \
18540                 the paired Caixa::declared_supervisor_slots \
18541                 presence-probe arm from the \
18542                 Caixa::validate_restart_window shared-codec gate and \
18543                 the Caixa::supervisor_view soft-swallowing fold",
18544            );
18545        }
18546    }
18547
18548    #[test]
18549    fn restart_window_projects_slice_by_borrow() {
18550        // The by-borrow pin: [`Caixa::restart_window`] returns
18551        // `Option<&str>` by borrow — the returned string slice borrows
18552        // the underlying `Option<String>` storage of the `:restart-window`
18553        // slot and the accessor must not clone on every call. Peer of
18554        // the sibling outer top-level [`Caixa`] `Option<&str>`-return
18555        // by-borrow pins on the universal-axis scalar family
18556        // (`licenca_projects_option_ref_by_borrow` /
18557        // `descricao_projects_option_ref_by_borrow` and siblings) —
18558        // extended onto the M2 supervisor-tree flat-spread
18559        // `Option<&str>` raw-duration-string axis.
18560        for window in [None, Some("60s"), Some("5m"), Some("")] {
18561            let c = caixa_with_restart_window(window);
18562            let first = c.restart_window();
18563            let second = c.restart_window();
18564            assert_eq!(
18565                first, second,
18566                "Caixa::restart_window must be idempotent — two \
18567                 successive calls on the same &self must return the \
18568                 same Option<&str>",
18569            );
18570            if let (Some(a), Some(b)) = (first, second) {
18571                assert_eq!(
18572                    a.as_ptr(),
18573                    b.as_ptr(),
18574                    "Caixa::restart_window must borrow the underlying \
18575                     String storage — two successive Some-arm calls must \
18576                     return slices with the same backing pointer (a fresh \
18577                     String clone would change the pointer on every call)",
18578                );
18579            }
18580            assert_eq!(
18581                first, window,
18582                "Caixa::restart_window must return :restart-window \
18583                 verbatim by borrow — got {first:?}, expected {window:?}",
18584            );
18585        }
18586    }
18587
18588    #[test]
18589    fn declared_supervisor_slots_restart_window_arm_routes_through_accessor() {
18590        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
18591        // `:restart-window` presence-probe arm must key off
18592        // [`Caixa::restart_window`], not the raw
18593        // `self.restart_window.is_some()` field-probe. Structurally:
18594        // every `Caixa { restart_window: Some(_), .. }` must push
18595        // `SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW` onto the declared-slot
18596        // list, and a `Caixa { restart_window: None, .. }` must NOT
18597        // push the label. Peer of the sibling
18598        // `declared_supervisor_slots_max_restarts_arm_routes_through_accessor`
18599        // routing pin.
18600        for window in ["60s", "5m", "1h", "500ms", "1.5s", ""] {
18601            let c = caixa_with_restart_window(Some(window));
18602            let slots = c.declared_supervisor_slots();
18603            assert!(
18604                slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
18605                "declared_supervisor_slots must push \
18606                 SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when \
18607                 `:restart-window` is Some({window:?}) — the accessor \
18608                 and the enumerator gate must route through the same \
18609                 substrate-primitive typed dispatch on the outer \
18610                 :restart-window presence bit (got slots={slots:?})",
18611            );
18612        }
18613        let c = caixa_with_restart_window(None);
18614        let slots = c.declared_supervisor_slots();
18615        assert!(
18616            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW),
18617            "declared_supervisor_slots must NOT push \
18618             SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW when `:restart-window` \
18619             is None — the author-omitted arm must route through the \
18620             accessor's None-return unchanged (got slots={slots:?})",
18621        );
18622    }
18623
18624    #[test]
18625    fn validate_restart_window_arm_routes_through_accessor() {
18626        // Composition pin: [`Caixa::validate_restart_window`]'s
18627        // shared-codec fold arm must key off [`Caixa::restart_window`],
18628        // not the raw `self.restart_window.as_deref()` field-projection.
18629        // Structurally: (1) `None` → `Ok(())` (the "omit the slot to
18630        // express no reset" canonical shape); (2) a canonical `Some`
18631        // arm (`"60s"`) → `Ok(())`; (3) a codec-rejected `Some` arm
18632        // (`"1.5s"`) → `Err(RestartWindowMalformed { restart_window,
18633        // .. })` carrying the offending raw string verbatim. The three
18634        // arms jointly pin that the validator's raw-string binding is
18635        // the accessor's return, not a peer projection — any future
18636        // silent detour that had the accessor collapse `Some("")` to
18637        // `None` would silently absorb the empty-after-trim refusal
18638        // case at the accessor boundary.
18639        caixa_with_restart_window(None)
18640            .validate_restart_window()
18641            .expect("None :restart-window must validate through the accessor");
18642        caixa_with_restart_window(Some("60s"))
18643            .validate_restart_window()
18644            .expect("canonical :restart-window \"60s\" must validate through the accessor");
18645        let err = caixa_with_restart_window(Some("1.5s"))
18646            .validate_restart_window()
18647            .expect_err("fractional-seconds :restart-window must fail through the accessor");
18648        assert!(
18649            matches!(
18650                err,
18651                ManifestError::RestartWindowMalformed { ref restart_window, .. }
18652                    if restart_window == "1.5s"
18653            ),
18654            "validator must carry the offending raw string verbatim \
18655             from the accessor's borrowed &str (got {err:?})",
18656        );
18657    }
18658
18659    #[test]
18660    fn supervisor_view_restart_window_arm_routes_through_accessor() {
18661        // Composition pin: [`Caixa::supervisor_view`]'s
18662        // per-`:restart-window` [`SupervisorSpec`] construction arm
18663        // must key off [`Caixa::restart_window`]'s soft-swallowing
18664        // `.and_then(|s| duration_codec::parse(s).ok())` fold, not the
18665        // raw `self.restart_window.as_deref().and_then(…)` field-fold.
18666        // Structurally: (1) `None` → `SupervisorSpec.restart_window ==
18667        // None` (the "never reset" sentinel); (2) canonical `Some("60s")`
18668        // → `SupervisorSpec.restart_window == Some(Duration::from_secs(60))`
18669        // (the shared codec's canonical parse); (3) codec-rejected
18670        // `Some("1.5s")` → `SupervisorSpec.restart_window == None`
18671        // (the soft-swallow preserving the view's best-effort shape).
18672        let c = caixa_supervisor_with_max_restarts_and_window(None, None);
18673        let view = c.supervisor_view().expect("Supervisor kind has a view");
18674        assert_eq!(
18675            view.restart_window(),
18676            None,
18677            "supervisor_view must project outer None :restart-window \
18678             onto None on the composed SupervisorSpec (never-reset \
18679             sentinel) through the accessor's None-return unchanged",
18680        );
18681
18682        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("60s"));
18683        let view = c.supervisor_view().expect("Supervisor kind has a view");
18684        assert_eq!(
18685            view.restart_window(),
18686            Some(std::time::Duration::from_secs(60)),
18687            "supervisor_view must fold outer Some(\"60s\") through the \
18688             shared duration_codec into Duration::from_secs(60) on the \
18689             composed SupervisorSpec (accessor's Some(&str) → codec \
18690             parse → Some(Duration))",
18691        );
18692
18693        let c = caixa_supervisor_with_max_restarts_and_window(None, Some("1.5s"));
18694        let view = c.supervisor_view().expect("Supervisor kind has a view");
18695        assert_eq!(
18696            view.restart_window(),
18697            None,
18698            "supervisor_view must soft-swallow the shared-codec parse \
18699             failure to None (the view's best-effort shape the sibling \
18700             manifest-level validate_restart_window surfaces as \
18701             RestartWindowMalformed); the accessor's raw-string return \
18702             is the single input every downstream consumer keys off",
18703        );
18704    }
18705
18706    // ── Caixa::upgrade_from — outer top-level &[UpgradeFromEntry] composite-slice accessor ──
18707
18708    fn caixa_with_upgrade_from(upgrade_from: Vec<crate::upgrade::UpgradeFromEntry>) -> Caixa {
18709        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
18710        c.upgrade_from = upgrade_from;
18711        c
18712    }
18713
18714    #[test]
18715    fn upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations() {
18716        // The canonical per-`Caixa` `:upgrade-from` M2 typed-slot
18717        // outer-composite `&[UpgradeFromEntry]`-return slice-shape
18718        // pin: [`Caixa::upgrade_from`] must return the `:upgrade-from`
18719        // typed `Vec<UpgradeFromEntry>` verbatim as a
18720        // `&[UpgradeFromEntry]` slice-view over the same backing
18721        // buffer the raw `self.upgrade_from.as_slice()` field access
18722        // borrows from, element-equal across every representative
18723        // fixture in the accept-set — `[]` (the "no hot-upgrade path
18724        // declared" arm every `defcaixa` without an `:upgrade-from`
18725        // block carries; `#[serde(default)]` folds an omitted slot
18726        // onto `Vec::new()`), a canonical single-entry `Restart`
18727        // fixture (the shape most Servicos carry — a single prior
18728        // version with the fallback strategy), a canonical multi-
18729        // entry list carrying every typed instruction variant
18730        // (`LoadModule` / `StateChange` / `SoftPurge` / `Purge` /
18731        // `Restart`), and a past-the-guard sentinel — a duplicate-
18732        // `:from` `[(0.1.0, Restart), (0.1.0, Restart)]` entry pair
18733        // ([`crate::upgrade::validate_upgrade_from`] rejects through
18734        // `DuplicateFrom { from: "0.1.0" }` but the accessor must
18735        // ship the raw slot verbatim so struct-literal fixtures
18736        // continue to expose the duplicate at the accessor boundary).
18737        //
18738        // Pins against a future silent detour that returned an owned
18739        // `Vec<UpgradeFromEntry>` (which would type-check but silently
18740        // clone on every accessor call, breaking the zero-cost
18741        // projection every peer sibling slice accessor carries), a
18742        // `[dup, dup] → [dup]` dedup collapse (which would silently
18743        // absorb the `DuplicateFrom` refusal case at the accessor
18744        // boundary and the [`crate::StandardLayout::verify`] cross-
18745        // entry gate would silently accept a struct-literal `Caixa`
18746        // carrying the drift), a reference to an operator-resolved
18747        // overlay (the future per-cluster `:upgrade-overrides` slot
18748        // — its resolution must land at exactly this accessor body,
18749        // not silently divert the raw slot away from a second
18750        // consumer), or an axis-shuffled projection (a future detour
18751        // that reordered entries through the accessor would silently
18752        // split the paired [`crate::StandardLayout::verify`] per-
18753        // `:upgrade-from` shape gate's traversal input from the peer
18754        // [`crate::render::servico_m2_overlay`] emitter's projection
18755        // input, since the operator's hot-upgrade dispatch matches
18756        // per-`:from` and axis reordering would silently split the
18757        // per-entry script-path existence probe's iteration order
18758        // from the M2 overlay emitter's serialized-entry order).
18759        //
18760        // First outer top-level [`Caixa`] `&[Composite]`-return
18761        // slice accessor pin on the substrate primitive for M2 / M3
18762        // typed-slot vec-carry axes — opens the outer-`Caixa`
18763        // `&[Composite]` composite-slice projection pattern the
18764        // sibling `:children` [`crate::supervisor::ChildSpec`] /
18765        // `:membros` [`crate::aplicacao::Membro`] / `:contratos`
18766        // [`crate::aplicacao::WitContract`] future outer-composite-
18767        // slice pins fold on. Peer of the closed outer-`Caixa`
18768        // scalar `Option<&Composite>` composite-reference family the
18769        // sibling `limits` / `behavior` / `politicas` / `placement`
18770        // / `entrada` `..._returns_..._option_ref_verbatim_across_
18771        // permutations` pins closed (b2bd9d7 → e4128e4) — extends
18772        // the "byte-equal, borrow-shared" outer-accessor discipline
18773        // onto the outer-`Caixa` `&[Composite]` vec-carry altitude.
18774        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18775        let fixtures: Vec<Vec<UpgradeFromEntry>> = vec![
18776            vec![],
18777            vec![UpgradeFromEntry {
18778                from: "0.0.1".into(),
18779                instructions: vec![UpgradeInstruction::Restart],
18780            }],
18781            vec![
18782                UpgradeFromEntry {
18783                    from: "0.0.1".into(),
18784                    instructions: vec![
18785                        UpgradeInstruction::LoadModule {
18786                            module: "demo".into(),
18787                        },
18788                        UpgradeInstruction::SoftPurge {
18789                            module: "demo".into(),
18790                        },
18791                    ],
18792                },
18793                UpgradeFromEntry {
18794                    from: "0.0.2".into(),
18795                    instructions: vec![
18796                        UpgradeInstruction::StateChange {
18797                            script: "servicos/upgrade.lisp".into(),
18798                        },
18799                        UpgradeInstruction::Purge {
18800                            module: "demo".into(),
18801                        },
18802                        UpgradeInstruction::Restart,
18803                    ],
18804                },
18805            ],
18806            vec![
18807                UpgradeFromEntry {
18808                    from: "0.1.0".into(),
18809                    instructions: vec![UpgradeInstruction::Restart],
18810                },
18811                UpgradeFromEntry {
18812                    from: "0.1.0".into(),
18813                    instructions: vec![UpgradeInstruction::Restart],
18814                },
18815            ],
18816        ];
18817        for upgrade_from in fixtures {
18818            let c = caixa_with_upgrade_from(upgrade_from.clone());
18819            assert_eq!(
18820                c.upgrade_from(),
18821                upgrade_from.as_slice(),
18822                "Caixa::upgrade_from must return :upgrade-from \
18823                 verbatim (got {:?}, expected {upgrade_from:?})",
18824                c.upgrade_from(),
18825            );
18826            assert_eq!(
18827                c.upgrade_from(),
18828                c.upgrade_from.as_slice(),
18829                "Caixa::upgrade_from must element-equal the raw \
18830                 `self.upgrade_from.as_slice()` field access across \
18831                 every value in the Vec<UpgradeFromEntry> accept-set",
18832            );
18833            assert_eq!(
18834                c.upgrade_from().is_empty(),
18835                c.upgrade_from.is_empty(),
18836                "Caixa::upgrade_from().is_empty() must byte-equal \
18837                 self.upgrade_from.is_empty() — a presence-bit drift \
18838                 would silently split the paired \
18839                 Caixa::declared_servico_slots M2 declared-slot \
18840                 enumerator's presence probe from the peer \
18841                 crate::render::servico_m2_overlay M2 overlay \
18842                 emitter's presence gate",
18843            );
18844        }
18845    }
18846
18847    #[test]
18848    fn declared_servico_slots_upgrade_from_arm_routes_through_accessor() {
18849        // Composition pin: [`Caixa::declared_servico_slots`]'s
18850        // `:upgrade-from` presence-probe arm must key off
18851        // [`Caixa::upgrade_from`], not the raw
18852        // `self.upgrade_from.is_empty()` field-probe. Structurally: a
18853        // `Caixa { upgrade_from: vec![UpgradeFromEntry { from: "0.0.1",
18854        // instructions: vec![Restart] }], .. }` must push
18855        // `M2_AUTHOR_KEY_UPGRADE_FROM` onto the declared-slot list
18856        // (the presence bit is non-empty, so the M2 kind-coherence
18857        // gate must surface the slot as "declared"), and a `Caixa {
18858        // upgrade_from: vec![], .. }` must NOT push the label (the
18859        // "author omitted the slot entirely" arm — the empty-slice
18860        // partition the serde-default folds onto). The pair jointly
18861        // pins the accessor + declared-slot enumerator composition:
18862        // any future silent detour that had the accessor collapse
18863        // `[Restart]` to `[]` (a `.filter(|e| !e.instructions.
18864        // is_empty())` projection) would silently absorb the
18865        // "declared but degenerate" arm at the accessor boundary and
18866        // the [`crate::LayoutError::ServicoSlotsOnNonServico`] kind-
18867        // coherence gate would silently accept a struct-literal
18868        // `Caixa` carrying the drift.
18869        //
18870        // Peer of the sibling
18871        // `declared_servico_slots_limits_arm_routes_through_accessor`
18872        // (b2bd9d7) and
18873        // `declared_servico_slots_behavior_arm_routes_through_accessor`
18874        // (35d8b52) composition pins on the sibling `:limits` /
18875        // `:behavior` outer-`Option<&Composite>` arms — same "the
18876        // enumerator gate must route through the substrate-primitive
18877        // typed dispatch" discipline extended onto the third M2
18878        // Servico-runtime slot axis, closing the enumerator's routing
18879        // invariant on every M2 arm.
18880        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18881        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
18882            from: "0.0.1".into(),
18883            instructions: vec![UpgradeInstruction::Restart],
18884        }]);
18885        let slots = c.declared_servico_slots();
18886        assert!(
18887            slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
18888            "declared_servico_slots must push \
18889             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
18890             non-empty — the accessor and the enumerator gate must \
18891             route through the same substrate-primitive typed \
18892             dispatch on the outer :upgrade-from presence bit (got \
18893             slots={slots:?})",
18894        );
18895        let c = caixa_with_upgrade_from(vec![]);
18896        let slots = c.declared_servico_slots();
18897        assert!(
18898            !slots.contains(&crate::render::M2_AUTHOR_KEY_UPGRADE_FROM),
18899            "declared_servico_slots must NOT push \
18900             M2_AUTHOR_KEY_UPGRADE_FROM when `:upgrade-from` is \
18901             empty — the author-omitted arm must route through the \
18902             accessor's empty-slice return unchanged (got \
18903             slots={slots:?})",
18904        );
18905    }
18906
18907    #[test]
18908    fn servico_m2_overlay_upgrade_from_arm_routes_through_accessor() {
18909        // Composition pin: [`crate::render::servico_m2_overlay`]'s
18910        // per-`:upgrade-from` M2 overlay emit arm must key off
18911        // [`Caixa::upgrade_from`], not the raw
18912        // `!caixa.upgrade_from.is_empty()` presence gate + the
18913        // `serde_yaml::to_value(&caixa.upgrade_from)` projection.
18914        // Structurally: a `Caixa { upgrade_from: vec![UpgradeFromEntry
18915        // { from: "0.0.1", instructions: vec![Restart] }], .. }` must
18916        // surface the `M2_KEY_UPGRADE_FROM` key with a per-entry
18917        // sequence in the overlay (the emitter fans onto the serde
18918        // slice-serialization), and a `Caixa { upgrade_from: vec![],
18919        // .. }` must omit the key entirely (the empty-slice
18920        // partition — the `!.is_empty()` outer gate elides the key
18921        // when the author omitted the slot). The pair jointly pins
18922        // the accessor + M2 overlay emitter composition: any future
18923        // silent detour that had the accessor return a fresh-cloned
18924        // `Vec<UpgradeFromEntry>` copy would silently break the
18925        // reference-identity pin the peer per-entry
18926        // `serde_yaml::to_value(caixa.upgrade_from())` projection
18927        // reads from — the projection would clone once per accessor
18928        // call instead of borrowing the storage buffer verbatim.
18929        //
18930        // Peer of the sibling
18931        // `servico_m2_overlay_limits_arm_routes_through_accessor`
18932        // (b2bd9d7) and
18933        // `servico_m2_overlay_behavior_arm_routes_through_accessor`
18934        // (35d8b52) composition pins on the sibling `:limits` /
18935        // `:behavior` outer-`Option<&Composite>` arms — same "the
18936        // M2 overlay emitter must route through the substrate-
18937        // primitive typed dispatch" discipline extended onto the
18938        // third M2 Servico-runtime slot axis, closing the overlay
18939        // emitter's routing invariant on every M2 arm.
18940        use crate::render::{M2_KEY_UPGRADE_FROM, servico_m2_overlay};
18941        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18942        let c = caixa_with_upgrade_from(vec![UpgradeFromEntry {
18943            from: "0.0.1".into(),
18944            instructions: vec![UpgradeInstruction::Restart],
18945        }]);
18946        let overlay = servico_m2_overlay(&c).unwrap();
18947        assert!(
18948            overlay.contains_key(M2_KEY_UPGRADE_FROM),
18949            "servico_m2_overlay must surface M2_KEY_UPGRADE_FROM when \
18950             `:upgrade-from` is non-empty — the accessor and the M2 \
18951             overlay emitter must route through the same substrate- \
18952             primitive typed dispatch on the outer :upgrade-from \
18953             slice (got overlay={overlay:?})",
18954        );
18955        let c = caixa_with_upgrade_from(vec![]);
18956        let overlay = servico_m2_overlay(&c).unwrap();
18957        assert!(
18958            !overlay.contains_key(M2_KEY_UPGRADE_FROM),
18959            "servico_m2_overlay must omit M2_KEY_UPGRADE_FROM when \
18960             `:upgrade-from` is empty — the empty-slice partition \
18961             must route through the accessor's empty-slice return \
18962             unchanged (got overlay={overlay:?})",
18963        );
18964    }
18965
18966    #[test]
18967    fn upgrade_from_projects_slice_by_borrow() {
18968        // The by-borrow pin: [`Caixa::upgrade_from`] returns
18969        // `&[UpgradeFromEntry]` by borrow — the returned slice
18970        // borrows the underlying `Vec<UpgradeFromEntry>` storage of
18971        // the `:upgrade-from` slot and the accessor must not clone
18972        // the backing `Vec` on every call. Peer of the sibling
18973        // outer top-level [`Caixa`] `&[T]`-return by-borrow pins
18974        // (`autores_projects_slice_by_borrow` b5d813f,
18975        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
18976        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
18977        // `exe_projects_slice_by_borrow` 65d9527,
18978        // `servicos_projects_slice_by_borrow` 611f78b,
18979        // `deps_projects_slice_by_borrow` ad34b4e,
18980        // `deps_dev_projects_slice_by_borrow` f7fd81e) on the
18981        // sibling outer top-level [`Caixa`] scalar-element `&[T]`
18982        // axes — extended here to the first outer-`Caixa`
18983        // composite-element `&[Composite]` axis: the accessor's
18984        // returned slice must borrow from `&self` (the returned
18985        // reference's lifetime is tied to `&self`), and calling the
18986        // accessor twice on the same [`Caixa`] must yield slices
18987        // that are pointer-equal (the underlying byte-buffer is the
18988        // storage `Vec`'s allocation, not a fresh copy) as well as
18989        // value-equal (idempotent, no side effects on `&self`).
18990        //
18991        // Pins against a future silent detour that returned an owned
18992        // `Vec<UpgradeFromEntry>` (which would type-check but
18993        // silently clone on every call), a `&Vec<UpgradeFromEntry>`
18994        // return (which would leak the backing `Vec`'s
18995        // grow/push/reserve surface no downstream consumer reaches
18996        // for), or a one-arm-only accessor that returned a
18997        // saturating value on some sentinel input.
18998        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
18999        for upgrade_from in [
19000            vec![],
19001            vec![UpgradeFromEntry {
19002                from: "0.0.1".into(),
19003                instructions: vec![UpgradeInstruction::Restart],
19004            }],
19005            vec![
19006                UpgradeFromEntry {
19007                    from: "0.0.1".into(),
19008                    instructions: vec![UpgradeInstruction::Restart],
19009                },
19010                UpgradeFromEntry {
19011                    from: "0.0.2".into(),
19012                    instructions: vec![UpgradeInstruction::SoftPurge {
19013                        module: "demo".into(),
19014                    }],
19015                },
19016            ],
19017        ] {
19018            let c = caixa_with_upgrade_from(upgrade_from.clone());
19019            let first = c.upgrade_from();
19020            let second = c.upgrade_from();
19021            assert_eq!(
19022                first, second,
19023                "Caixa::upgrade_from must be idempotent — two \
19024                 successive calls on the same &self must return the \
19025                 same &[UpgradeFromEntry]",
19026            );
19027            assert_eq!(
19028                first.as_ptr(),
19029                second.as_ptr(),
19030                "Caixa::upgrade_from must borrow the underlying \
19031                 Vec<UpgradeFromEntry> storage — two successive calls \
19032                 must return slices with the same backing pointer (a \
19033                 fresh Vec<UpgradeFromEntry> clone would change the \
19034                 pointer on every call)",
19035            );
19036            assert_eq!(
19037                first,
19038                upgrade_from.as_slice(),
19039                "Caixa::upgrade_from must return :upgrade-from \
19040                 verbatim by borrow — got {first:?}, expected \
19041                 {upgrade_from:?}",
19042            );
19043        }
19044    }
19045
19046    // ── Caixa::children — outer top-level &[ChildSpec] composite-slice accessor ──
19047
19048    fn caixa_with_children(children: Vec<crate::supervisor::ChildSpec>) -> Caixa {
19049        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19050        c.children = children;
19051        c
19052    }
19053
19054    #[test]
19055    fn children_returns_children_slice_verbatim_across_permutations() {
19056        // The canonical per-`Caixa` `:children` M2 supervisor-tree-slot
19057        // outer-composite `&[ChildSpec]`-return slice-shape pin:
19058        // [`Caixa::children`] must return the `:children` typed
19059        // `Vec<ChildSpec>` verbatim as a `&[ChildSpec]` slice-view over
19060        // the same backing buffer the raw `self.children.as_slice()`
19061        // field access borrows from, element-equal across every
19062        // representative fixture in the accept-set — `[]` (the "no
19063        // static children declared" arm every non-`Supervisor`-kind
19064        // `defcaixa` carries by `#[serde(default)]` and every
19065        // `SimpleOneForOne` supervisor carries by cross-slot refusal),
19066        // a canonical single-child `Permanent` fixture (the shape
19067        // most `OneForOne` supervisors carry — a single long-running
19068        // worker child), a canonical multi-child list carrying every
19069        // typed restart-policy variant (`Permanent` / `Transient` /
19070        // `Temporary`), and a past-the-guard sentinel — a duplicate
19071        // `:caixa` `[("w", ...), ("w", ...)]` entry pair
19072        // ([`crate::SupervisorSpec::validate`] rejects through
19073        // `DuplicateChildNome { nome: "w" }` but the accessor must
19074        // ship the raw slot verbatim so struct-literal fixtures
19075        // continue to expose the duplicate at the accessor boundary).
19076        //
19077        // Pins against a future silent detour that returned an owned
19078        // `Vec<ChildSpec>` (which would type-check but silently clone
19079        // on every accessor call, breaking the zero-cost projection
19080        // every peer sibling slice accessor carries), a `[dup, dup] →
19081        // [dup]` dedup collapse (which would silently absorb the
19082        // `DuplicateChildNome` refusal case at the accessor boundary
19083        // and the [`crate::StandardLayout::verify`] cross-child gate
19084        // would silently accept a struct-literal `Caixa` carrying the
19085        // drift), a reference to an operator-resolved overlay (the
19086        // future per-cluster `:children-overrides` slot — its
19087        // resolution must land at exactly this accessor body, not
19088        // silently divert the raw slot away from a second consumer),
19089        // or an axis-shuffled projection (a future detour that
19090        // reordered children through the accessor would silently
19091        // split the paired [`crate::StandardLayout::verify`] per-
19092        // supervisor gate's traversal input from the peer
19093        // [`Self::supervisor_view`] fold-in path's clone-order input,
19094        // since the OTP `RestForOne` restart strategy dispatches on
19095        // declared child order and axis reordering would silently
19096        // split the operator's per-cluster restart-fan-out order
19097        // from the caixa.lisp source-order).
19098        //
19099        // Second outer top-level [`Caixa`] `&[Composite]`-return slice
19100        // accessor pin on the substrate primitive for M2 / M3 typed-
19101        // slot vec-carry axes — folds on the outer-`Caixa`
19102        // `&[Composite]` composite-slice sub-family the sibling
19103        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19104        // (2a1f907) pin opened, peer at the outer altitude of the
19105        // closed inner-`SupervisorSpec` `SupervisorSpec::children`
19106        // (bc92bce) accessor on the same OTP-supervisor static-child-
19107        // list axis.
19108        use crate::supervisor::{ChildSpec, RestartPolicy};
19109        let fixtures: Vec<Vec<ChildSpec>> = vec![
19110            vec![],
19111            vec![ChildSpec {
19112                caixa: "worker".into(),
19113                versao: "^0.1".into(),
19114                restart: RestartPolicy::Permanent,
19115            }],
19116            vec![
19117                ChildSpec {
19118                    caixa: "worker-a".into(),
19119                    versao: "^0.1".into(),
19120                    restart: RestartPolicy::Permanent,
19121                },
19122                ChildSpec {
19123                    caixa: "worker-b".into(),
19124                    versao: "^0.1".into(),
19125                    restart: RestartPolicy::Transient,
19126                },
19127                ChildSpec {
19128                    caixa: "worker-c".into(),
19129                    versao: "^0.1".into(),
19130                    restart: RestartPolicy::Temporary,
19131                },
19132            ],
19133            vec![
19134                ChildSpec {
19135                    caixa: "w".into(),
19136                    versao: "^0.1".into(),
19137                    restart: RestartPolicy::Permanent,
19138                },
19139                ChildSpec {
19140                    caixa: "w".into(),
19141                    versao: "^0.1".into(),
19142                    restart: RestartPolicy::Permanent,
19143                },
19144            ],
19145        ];
19146        for children in fixtures {
19147            let c = caixa_with_children(children.clone());
19148            assert_eq!(
19149                c.children(),
19150                children.as_slice(),
19151                "Caixa::children must return :children verbatim \
19152                 (got {:?}, expected {children:?})",
19153                c.children(),
19154            );
19155            assert_eq!(
19156                c.children(),
19157                c.children.as_slice(),
19158                "Caixa::children must element-equal the raw \
19159                 `self.children.as_slice()` field access across \
19160                 every value in the Vec<ChildSpec> accept-set",
19161            );
19162            assert_eq!(
19163                c.children().is_empty(),
19164                c.children.is_empty(),
19165                "Caixa::children().is_empty() must byte-equal \
19166                 self.children.is_empty() — a presence-bit drift \
19167                 would silently split the paired \
19168                 Caixa::declared_supervisor_slots supervisor-tree \
19169                 declared-slot enumerator's presence probe from the \
19170                 peer Caixa::supervisor_view typed-view composer's \
19171                 fold-in path",
19172            );
19173        }
19174    }
19175
19176    #[test]
19177    fn declared_supervisor_slots_children_arm_routes_through_accessor() {
19178        // Composition pin: [`Caixa::declared_supervisor_slots`]'s
19179        // `:children` presence-probe arm must key off
19180        // [`Caixa::children`], not the raw
19181        // `!self.children.is_empty()` field-probe. Structurally: a
19182        // `Caixa { children: vec![ChildSpec { caixa: "w", versao:
19183        // "^0.1", restart: Permanent }], .. }` must push
19184        // `SUPERVISOR_AUTHOR_KEY_CHILDREN` onto the declared-slot list
19185        // (the presence bit is non-empty, so the supervisor-tree
19186        // kind-coherence gate must surface the slot as "declared"),
19187        // and a `Caixa { children: vec![], .. }` must NOT push the
19188        // label (the "author omitted the slot entirely" arm — the
19189        // empty-slice partition the serde-default folds onto). The
19190        // pair jointly pins the accessor + declared-slot enumerator
19191        // composition: any future silent detour that had the accessor
19192        // collapse `[Permanent]` to `[]` (a `.filter(|c| c.nome() !=
19193        // "__reserved__")` projection) would silently absorb the
19194        // "declared but degenerate" arm at the accessor boundary and
19195        // the [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
19196        // kind-coherence gate would silently accept a struct-literal
19197        // `Caixa` carrying the drift.
19198        //
19199        // Peer of the sibling
19200        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19201        // (2a1f907) on the M2 `:upgrade-from` composite-slice arm —
19202        // same "the enumerator gate must route through the substrate-
19203        // primitive typed dispatch" discipline extended onto the
19204        // supervisor-tree `:children` composite-slice arm.
19205        use crate::supervisor::{ChildSpec, RestartPolicy};
19206        let c = caixa_with_children(vec![ChildSpec {
19207            caixa: "w".into(),
19208            versao: "^0.1".into(),
19209            restart: RestartPolicy::Permanent,
19210        }]);
19211        let slots = c.declared_supervisor_slots();
19212        assert!(
19213            slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
19214            "declared_supervisor_slots must push \
19215             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
19216             non-empty — the accessor and the enumerator gate must \
19217             route through the same substrate-primitive typed \
19218             dispatch on the outer :children presence bit (got \
19219             slots={slots:?})",
19220        );
19221        let c = caixa_with_children(vec![]);
19222        let slots = c.declared_supervisor_slots();
19223        assert!(
19224            !slots.contains(&crate::render::SUPERVISOR_AUTHOR_KEY_CHILDREN),
19225            "declared_supervisor_slots must NOT push \
19226             SUPERVISOR_AUTHOR_KEY_CHILDREN when `:children` is \
19227             empty — the author-omitted arm must route through the \
19228             accessor's empty-slice return unchanged (got \
19229             slots={slots:?})",
19230        );
19231    }
19232
19233    #[test]
19234    fn supervisor_view_children_arm_routes_through_accessor() {
19235        // Composition pin: [`Caixa::supervisor_view`]'s per-`:children`
19236        // fold-in arm must key off [`Caixa::children`], not the raw
19237        // `self.children.clone()` field-clone. Structurally: a `Caixa {
19238        // kind: Supervisor, estrategia: Some(OneForOne), children:
19239        // vec![ChildSpec { caixa: "w", .. }], .. }` must fold the
19240        // per-child list through the accessor into the typed
19241        // [`SupervisorSpec`] view's `children` field verbatim — every
19242        // entry the accessor surfaces must land in the view's
19243        // `children` slot in the same order. The pair jointly pins the
19244        // accessor + view-composer composition: any future silent
19245        // detour that had the accessor return a fresh-cloned
19246        // `Vec<ChildSpec>` copy would silently break the reference-
19247        // identity pin the peer `supervisor_view` fold-in path reads
19248        // from — the fold would clone once more per accessor call
19249        // instead of borrowing the storage buffer verbatim once.
19250        //
19251        // Peer of the sibling
19252        // `supervisor_view_kind_gate_routes_through_accessor` (35d8b52-
19253        // family) composition pin on the peer kind-gate arm — same
19254        // "the view composer must route through the substrate-
19255        // primitive typed dispatch" discipline extended onto the
19256        // per-`:children` fold-in arm, closing the supervisor-view
19257        // composer's routing invariant on the composite-slice input.
19258        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
19259        let mut c = caixa_with_children(vec![
19260            ChildSpec {
19261                caixa: "worker-a".into(),
19262                versao: "^0.1".into(),
19263                restart: RestartPolicy::Permanent,
19264            },
19265            ChildSpec {
19266                caixa: "worker-b".into(),
19267                versao: "^0.1".into(),
19268                restart: RestartPolicy::Transient,
19269            },
19270        ]);
19271        c.kind = crate::CaixaKind::Supervisor;
19272        c.estrategia = Some(RestartStrategy::OneForOne);
19273        let view = c
19274            .supervisor_view()
19275            .expect("Supervisor kind must produce a supervisor_view");
19276        assert_eq!(
19277            view.children(),
19278            c.children(),
19279            "supervisor_view must fold Caixa::children verbatim into \
19280             SupervisorSpec::children — the accessor and the view \
19281             composer must route through the same substrate-primitive \
19282             typed dispatch on the outer :children slice (got view \
19283             children={:?}, expected {:?})",
19284            view.children(),
19285            c.children(),
19286        );
19287    }
19288
19289    #[test]
19290    fn children_projects_slice_by_borrow() {
19291        // The by-borrow pin: [`Caixa::children`] returns
19292        // `&[ChildSpec]` by borrow — the returned slice borrows the
19293        // underlying `Vec<ChildSpec>` storage of the `:children` slot
19294        // and the accessor must not clone the backing `Vec` on every
19295        // call. Peer of the sibling outer top-level [`Caixa`]
19296        // `&[T]`-return by-borrow pins (`autores_projects_slice_by_borrow`
19297        // b5d813f, `etiquetas_projects_slice_by_borrow` 78c7d3c,
19298        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19299        // `exe_projects_slice_by_borrow` 65d9527,
19300        // `servicos_projects_slice_by_borrow` 611f78b,
19301        // `deps_projects_slice_by_borrow` ad34b4e,
19302        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19303        // `upgrade_from_projects_slice_by_borrow` 2a1f907) on the
19304        // sibling outer top-level [`Caixa`] scalar-element and
19305        // composite-element `&[T]` axes — folds on the outer-`Caixa`
19306        // composite-element `&[Composite]` axis: the accessor's
19307        // returned slice must borrow from `&self` (the returned
19308        // reference's lifetime is tied to `&self`), and calling the
19309        // accessor twice on the same [`Caixa`] must yield slices
19310        // that are pointer-equal (the underlying byte-buffer is the
19311        // storage `Vec`'s allocation, not a fresh copy) as well as
19312        // value-equal (idempotent, no side effects on `&self`).
19313        //
19314        // Pins against a future silent detour that returned an owned
19315        // `Vec<ChildSpec>` (which would type-check but silently clone
19316        // on every call), a `&Vec<ChildSpec>` return (which would leak
19317        // the backing `Vec`'s grow/push/reserve surface no downstream
19318        // consumer reaches for), or a one-arm-only accessor that
19319        // returned a saturating value on some sentinel input.
19320        use crate::supervisor::{ChildSpec, RestartPolicy};
19321        for children in [
19322            vec![],
19323            vec![ChildSpec {
19324                caixa: "w".into(),
19325                versao: "^0.1".into(),
19326                restart: RestartPolicy::Permanent,
19327            }],
19328            vec![
19329                ChildSpec {
19330                    caixa: "worker-a".into(),
19331                    versao: "^0.1".into(),
19332                    restart: RestartPolicy::Permanent,
19333                },
19334                ChildSpec {
19335                    caixa: "worker-b".into(),
19336                    versao: "^0.1".into(),
19337                    restart: RestartPolicy::Transient,
19338                },
19339            ],
19340        ] {
19341            let c = caixa_with_children(children.clone());
19342            let first = c.children();
19343            let second = c.children();
19344            assert_eq!(
19345                first, second,
19346                "Caixa::children must be idempotent — two successive \
19347                 calls on the same &self must return the same \
19348                 &[ChildSpec]",
19349            );
19350            assert_eq!(
19351                first.as_ptr(),
19352                second.as_ptr(),
19353                "Caixa::children must borrow the underlying \
19354                 Vec<ChildSpec> storage — two successive calls must \
19355                 return slices with the same backing pointer (a fresh \
19356                 Vec<ChildSpec> clone would change the pointer on \
19357                 every call)",
19358            );
19359            assert_eq!(
19360                first,
19361                children.as_slice(),
19362                "Caixa::children must return :children verbatim by \
19363                 borrow — got {first:?}, expected {children:?}",
19364            );
19365        }
19366    }
19367
19368    // ── Caixa::membros — outer top-level &[Membro] composite-slice accessor ──
19369
19370    fn caixa_aplicacao_with_membros(membros: Vec<crate::aplicacao::Membro>) -> Caixa {
19371        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19372        c.kind = CaixaKind::Aplicacao;
19373        c.membros = membros;
19374        c
19375    }
19376
19377    #[test]
19378    fn membros_returns_membros_slice_verbatim_across_permutations() {
19379        // The canonical per-`Caixa` `:membros` M3 mesh-slot outer-
19380        // composite `&[Membro]`-return slice-shape pin:
19381        // [`Caixa::membros`] must return the `:membros` typed
19382        // `Vec<Membro>` verbatim as a `&[Membro]` slice-view over the
19383        // same backing buffer the raw `self.membros.as_slice()` field
19384        // access borrows from, element-equal across every
19385        // representative fixture in the accept-set — `[]` (the "no
19386        // members declared" arm every non-`Aplicacao`-kind `defcaixa`
19387        // carries by `#[serde(default)]` and every partially-authored
19388        // Aplicacao carries before the
19389        // [`crate::AplicacaoError::MembrosEmpty`] gate fires), a
19390        // canonical single-member fixture (the shape a minimal
19391        // Aplicacao carries — one Servico wrapping one contained
19392        // computation), a canonical multi-member list carrying three
19393        // distinct entries (the canonical checkout-shape Aplicacao —
19394        // cart / pricing / auth — every canonical example carries), and
19395        // a past-the-guard sentinel — a duplicate `:caixa`
19396        // `[("cart", ...), ("cart", ...)]` entry pair
19397        // ([`crate::AplicacaoSpec::validate`] rejects through
19398        // `DuplicateMembro { nome: "cart" }` but the accessor must ship
19399        // the raw slot verbatim so struct-literal fixtures continue to
19400        // expose the duplicate at the accessor boundary).
19401        //
19402        // Pins against a future silent detour that returned an owned
19403        // `Vec<Membro>` (which would type-check but silently clone on
19404        // every accessor call, breaking the zero-cost projection every
19405        // peer sibling slice accessor carries), a `[dup, dup] → [dup]`
19406        // dedup collapse (which would silently absorb the
19407        // `DuplicateMembro` refusal case at the accessor boundary and
19408        // the [`crate::StandardLayout::verify`] cross-member gate would
19409        // silently accept a struct-literal `Caixa` carrying the drift),
19410        // a reference to an operator-resolved overlay (the future per-
19411        // cluster `:membros-overrides` slot — its resolution must land
19412        // at exactly this accessor body, not silently divert the raw
19413        // slot away from a second consumer), or an axis-shuffled
19414        // projection (a future detour that reordered members through
19415        // the accessor would silently split the paired
19416        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
19417        // traversal input from the peer [`Self::aplicacao_view`] fold-
19418        // in path's clone-order input, since the canonical `:contratos`
19419        // `:de`/`:para` and `:entrada :para` cross-slot refusal probes
19420        // read the member set through the same slice).
19421        //
19422        // Third outer top-level [`Caixa`] `&[Composite]`-return slice
19423        // accessor pin on the substrate primitive for M2 / M3 typed-
19424        // slot vec-carry axes — opens the outer-`Caixa` M3 mesh-slot
19425        // arm of the `&[Composite]` composite-slice sub-family the
19426        // sibling M2 `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19427        // (2a1f907) and
19428        // `children_returns_children_slice_verbatim_across_permutations`
19429        // (c17b51e) pins opened, peer at the outer altitude of the
19430        // closed inner-[`crate::AplicacaoSpec::membros`] (6c77e36)
19431        // accessor on the same MESH-COMPOSITION per-Aplicacao member-
19432        // list axis.
19433        use crate::aplicacao::Membro;
19434        let fixtures: Vec<Vec<Membro>> = vec![
19435            vec![],
19436            vec![Membro {
19437                caixa: "cart".into(),
19438                versao: "^0.1".into(),
19439            }],
19440            vec![
19441                Membro {
19442                    caixa: "cart".into(),
19443                    versao: "^0.1".into(),
19444                },
19445                Membro {
19446                    caixa: "pricing".into(),
19447                    versao: "^0.2".into(),
19448                },
19449                Membro {
19450                    caixa: "auth".into(),
19451                    versao: "^1.0".into(),
19452                },
19453            ],
19454            vec![
19455                Membro {
19456                    caixa: "cart".into(),
19457                    versao: "^0.1".into(),
19458                },
19459                Membro {
19460                    caixa: "cart".into(),
19461                    versao: "^0.1".into(),
19462                },
19463            ],
19464        ];
19465        for membros in fixtures {
19466            let c = caixa_aplicacao_with_membros(membros.clone());
19467            assert_eq!(
19468                c.membros(),
19469                membros.as_slice(),
19470                "Caixa::membros must return :membros verbatim \
19471                 (got {:?}, expected {membros:?})",
19472                c.membros(),
19473            );
19474            assert_eq!(
19475                c.membros(),
19476                c.membros.as_slice(),
19477                "Caixa::membros must element-equal the raw \
19478                 `self.membros.as_slice()` field access across every \
19479                 value in the Vec<Membro> accept-set",
19480            );
19481            assert_eq!(
19482                c.membros().is_empty(),
19483                c.membros.is_empty(),
19484                "Caixa::membros().is_empty() must byte-equal \
19485                 self.membros.is_empty() — a presence-bit drift would \
19486                 silently split the paired Caixa::declared_mesh_slots \
19487                 mesh declared-slot enumerator's presence probe from \
19488                 the peer Caixa::aplicacao_view typed-view composer's \
19489                 fold-in path",
19490            );
19491        }
19492    }
19493
19494    #[test]
19495    fn declared_mesh_slots_membros_arm_routes_through_accessor() {
19496        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:membros`
19497        // presence-probe arm must key off [`Caixa::membros`], not the
19498        // raw `!self.membros.is_empty()` field-probe. Structurally: a
19499        // `Caixa { membros: vec![Membro { caixa: "cart", versao:
19500        // "^0.1" }], .. }` must push `M3_AUTHOR_KEY_MEMBROS` onto the
19501        // declared-slot list (the presence bit is non-empty, so the
19502        // mesh kind-coherence gate must surface the slot as
19503        // "declared"), and a `Caixa { membros: vec![], .. }` must NOT
19504        // push the label (the "author omitted the slot entirely" arm
19505        // — the empty-slice partition the serde-default folds onto).
19506        // The pair jointly pins the accessor + declared-slot
19507        // enumerator composition: any future silent detour that had
19508        // the accessor collapse `[Membro { .. }]` to `[]` (a
19509        // `.filter(|m| m.nome() != "__reserved__")` projection) would
19510        // silently absorb the "declared but degenerate" arm at the
19511        // accessor boundary and the
19512        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
19513        // coherence gate would silently accept a struct-literal
19514        // `Caixa` carrying the drift.
19515        //
19516        // Peer of the sibling
19517        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19518        // (2a1f907) and
19519        // `declared_supervisor_slots_children_arm_routes_through_accessor`
19520        // (c17b51e) composition pins on the M2 `:upgrade-from` /
19521        // `:children` composite-slice arms — same "the enumerator gate
19522        // must route through the substrate-primitive typed dispatch"
19523        // discipline extended onto the M3 `:membros` composite-slice
19524        // arm, opening the M3 arm of the declared-slot enumerator's
19525        // routing invariant.
19526        use crate::aplicacao::Membro;
19527        let c = caixa_aplicacao_with_membros(vec![Membro {
19528            caixa: "cart".into(),
19529            versao: "^0.1".into(),
19530        }]);
19531        let slots = c.declared_mesh_slots();
19532        assert!(
19533            slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
19534            "declared_mesh_slots must push M3_AUTHOR_KEY_MEMBROS when \
19535             `:membros` is non-empty — the accessor and the enumerator \
19536             gate must route through the same substrate-primitive \
19537             typed dispatch on the outer :membros presence bit (got \
19538             slots={slots:?})",
19539        );
19540        let c = caixa_aplicacao_with_membros(vec![]);
19541        let slots = c.declared_mesh_slots();
19542        assert!(
19543            !slots.contains(&crate::render::M3_AUTHOR_KEY_MEMBROS),
19544            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_MEMBROS \
19545             when `:membros` is empty — the author-omitted arm must \
19546             route through the accessor's empty-slice return unchanged \
19547             (got slots={slots:?})",
19548        );
19549    }
19550
19551    #[test]
19552    fn aplicacao_view_membros_arm_routes_through_accessor() {
19553        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:membros`
19554        // fold-in arm must key off [`Caixa::membros`], not the raw
19555        // `self.membros.clone()` field-clone. Structurally: a `Caixa {
19556        // kind: Aplicacao, membros: vec![Membro { caixa: "cart", .. },
19557        // Membro { caixa: "pricing", .. }], .. }` must fold the per-
19558        // member list through the accessor into the typed
19559        // [`crate::AplicacaoSpec`] view's `membros` slot verbatim —
19560        // every entry the accessor surfaces must land in the view's
19561        // `membros` slot in the same order. The pair jointly pins the
19562        // accessor + view-composer composition: any future silent
19563        // detour that had the accessor return a fresh-cloned
19564        // `Vec<Membro>` copy would silently break the reference-
19565        // identity pin the peer `aplicacao_view` fold-in path reads
19566        // from — the fold would clone once more per accessor call
19567        // instead of borrowing the storage buffer verbatim once.
19568        //
19569        // Peer of the sibling
19570        // `aplicacao_view_politicas_arm_folds_through_accessor`
19571        // (5d23d29) /
19572        // `aplicacao_view_placement_arm_folds_through_accessor`
19573        // (4fb8074) /
19574        // `aplicacao_view_entrada_arm_folds_through_accessor` (e4128e4)
19575        // composition pins on the M3 `:politicas` / `:placement` /
19576        // `:entrada` outer-`Option<&Composite>` arms — extended here to
19577        // the M3 `:membros` outer-`&[Composite]` composite-slice arm,
19578        // closing the aplicacao-view composer's routing invariant on
19579        // the composite-slice input.
19580        use crate::aplicacao::Membro;
19581        let c = caixa_aplicacao_with_membros(vec![
19582            Membro {
19583                caixa: "cart".into(),
19584                versao: "^0.1".into(),
19585            },
19586            Membro {
19587                caixa: "pricing".into(),
19588                versao: "^0.2".into(),
19589            },
19590        ]);
19591        let view = c
19592            .aplicacao_view()
19593            .expect("Aplicacao kind must produce an aplicacao_view");
19594        assert_eq!(
19595            view.membros(),
19596            c.membros(),
19597            "aplicacao_view must fold Caixa::membros verbatim into \
19598             AplicacaoSpec::membros — the accessor and the view \
19599             composer must route through the same substrate-primitive \
19600             typed dispatch on the outer :membros slice (got view \
19601             membros={:?}, expected {:?})",
19602            view.membros(),
19603            c.membros(),
19604        );
19605    }
19606
19607    #[test]
19608    fn membros_projects_slice_by_borrow() {
19609        // The by-borrow pin: [`Caixa::membros`] returns `&[Membro]` by
19610        // borrow — the returned slice borrows the underlying
19611        // `Vec<Membro>` storage of the `:membros` slot and the
19612        // accessor must not clone the backing `Vec` on every call.
19613        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
19614        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
19615        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
19616        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19617        // `exe_projects_slice_by_borrow` 65d9527,
19618        // `servicos_projects_slice_by_borrow` 611f78b,
19619        // `deps_projects_slice_by_borrow` ad34b4e,
19620        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19621        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
19622        // `children_projects_slice_by_borrow` c17b51e) on the sibling
19623        // outer top-level [`Caixa`] scalar-element and composite-
19624        // element `&[T]` axes — folds on the outer-`Caixa` M3 mesh-
19625        // slot composite-element `&[Composite]` axis: the accessor's
19626        // returned slice must borrow from `&self` (the returned
19627        // reference's lifetime is tied to `&self`), and calling the
19628        // accessor twice on the same [`Caixa`] must yield slices that
19629        // are pointer-equal (the underlying byte-buffer is the storage
19630        // `Vec`'s allocation, not a fresh copy) as well as value-equal
19631        // (idempotent, no side effects on `&self`).
19632        //
19633        // Pins against a future silent detour that returned an owned
19634        // `Vec<Membro>` (which would type-check but silently clone on
19635        // every call), a `&Vec<Membro>` return (which would leak the
19636        // backing `Vec`'s grow/push/reserve surface no downstream
19637        // consumer reaches for), or a one-arm-only accessor that
19638        // returned a saturating value on some sentinel input.
19639        use crate::aplicacao::Membro;
19640        for membros in [
19641            vec![],
19642            vec![Membro {
19643                caixa: "cart".into(),
19644                versao: "^0.1".into(),
19645            }],
19646            vec![
19647                Membro {
19648                    caixa: "cart".into(),
19649                    versao: "^0.1".into(),
19650                },
19651                Membro {
19652                    caixa: "pricing".into(),
19653                    versao: "^0.2".into(),
19654                },
19655            ],
19656        ] {
19657            let c = caixa_aplicacao_with_membros(membros.clone());
19658            let first = c.membros();
19659            let second = c.membros();
19660            assert_eq!(
19661                first, second,
19662                "Caixa::membros must be idempotent — two successive \
19663                 calls on the same &self must return the same &[Membro]",
19664            );
19665            assert_eq!(
19666                first.as_ptr(),
19667                second.as_ptr(),
19668                "Caixa::membros must borrow the underlying Vec<Membro> \
19669                 storage — two successive calls must return slices with \
19670                 the same backing pointer (a fresh Vec<Membro> clone \
19671                 would change the pointer on every call)",
19672            );
19673            assert_eq!(
19674                first,
19675                membros.as_slice(),
19676                "Caixa::membros must return :membros verbatim by borrow \
19677                 — got {first:?}, expected {membros:?}",
19678            );
19679        }
19680    }
19681
19682    // ── Caixa::contratos — outer top-level &[WitContract] composite-slice accessor ──
19683
19684    fn caixa_aplicacao_with_contratos(contratos: Vec<crate::aplicacao::WitContract>) -> Caixa {
19685        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19686        c.kind = CaixaKind::Aplicacao;
19687        c.contratos = contratos;
19688        c
19689    }
19690
19691    fn contrato_http_for_test(
19692        de: &str,
19693        para: &str,
19694        endpoint: &str,
19695    ) -> crate::aplicacao::WitContract {
19696        crate::aplicacao::WitContract {
19697            de: de.into(),
19698            para: para.into(),
19699            wit: "wasi:http/proxy".into(),
19700            endpoint: Some(endpoint.into()),
19701            subject: None,
19702            slot: None,
19703        }
19704    }
19705
19706    #[test]
19707    fn contratos_returns_contratos_slice_verbatim_across_permutations() {
19708        // The canonical per-`Caixa` `:contratos` M3 mesh-slot outer-
19709        // composite `&[WitContract]`-return slice-shape pin:
19710        // [`Caixa::contratos`] must return the `:contratos` typed
19711        // `Vec<WitContract>` verbatim as a `&[WitContract]` slice-view
19712        // over the same backing buffer the raw
19713        // `self.contratos.as_slice()` field access borrows from,
19714        // element-equal across every representative fixture in the
19715        // accept-set — `[]` (the "no contracts declared" arm every
19716        // non-`Aplicacao`-kind `defcaixa` carries by
19717        // `#[serde(default)]` and every leaf-Aplicacao with a single
19718        // member carries), a canonical single-edge fixture (the
19719        // minimal directed-graph shape: one HTTP-shape `(cart → catalog)`
19720        // edge), and a canonical multi-edge fixture with three distinct
19721        // edges (the checkout-shape Aplicacao's HTTP-fan pattern:
19722        // `(cart → catalog)`, `(cart → pricing)`, `(cart → auth)`).
19723        //
19724        // Pins against a future silent detour that returned an owned
19725        // `Vec<WitContract>` (which would type-check but silently clone
19726        // on every accessor call, breaking the zero-cost projection
19727        // every peer sibling slice accessor carries), an axis-shuffled
19728        // projection (a future detour that reordered edges through the
19729        // accessor would silently split the paired
19730        // [`crate::StandardLayout::verify`] per-Aplicacao gate's
19731        // traversal input from the peer [`Self::aplicacao_view`] fold-
19732        // in path's clone-order input, since every canonical
19733        // `caixa-mesh` renderer's per-`(:de, :para)` adjacency-list
19734        // seed dispatch reads the edge set through the same slice),
19735        // or a reference to an operator-resolved overlay (the future
19736        // per-cluster `:contratos-overrides` slot — its resolution
19737        // must land at exactly this accessor body, not silently divert
19738        // the raw slot away from a second consumer).
19739        //
19740        // Fourth outer top-level [`Caixa`] `&[Composite]`-return slice
19741        // accessor pin on the substrate primitive for M2 / M3 typed-
19742        // slot vec-carry axes — closes the outer-`Caixa`
19743        // `&[Composite]` composite-slice sub-family the sibling M2
19744        // `upgrade_from_returns_upgrade_from_slice_verbatim_across_permutations`
19745        // (2a1f907) and
19746        // `children_returns_children_slice_verbatim_across_permutations`
19747        // (c17b51e) pins opened and the M3
19748        // `membros_returns_membros_slice_verbatim_across_permutations`
19749        // (0f26987) pin folded on, closing the outer-`Caixa` M3 mesh-
19750        // slot arm of the composite-slice sub-family. Peer at the outer
19751        // altitude of the closed inner-
19752        // [`crate::AplicacaoSpec::contratos`] (0dcc926) accessor on the
19753        // same MESH-COMPOSITION per-Aplicacao contract-list axis.
19754        let fixtures: Vec<Vec<crate::aplicacao::WitContract>> = vec![
19755            vec![],
19756            vec![contrato_http_for_test("cart", "catalog", "/items")],
19757            vec![
19758                contrato_http_for_test("cart", "catalog", "/items"),
19759                contrato_http_for_test("cart", "pricing", "/price"),
19760                contrato_http_for_test("cart", "auth", "/whoami"),
19761            ],
19762        ];
19763        for contratos in fixtures {
19764            let c = caixa_aplicacao_with_contratos(contratos.clone());
19765            assert_eq!(
19766                c.contratos(),
19767                contratos.as_slice(),
19768                "Caixa::contratos must return :contratos verbatim \
19769                 (got {:?}, expected {contratos:?})",
19770                c.contratos(),
19771            );
19772            assert_eq!(
19773                c.contratos(),
19774                c.contratos.as_slice(),
19775                "Caixa::contratos must element-equal the raw \
19776                 `self.contratos.as_slice()` field access across every \
19777                 value in the Vec<WitContract> accept-set",
19778            );
19779            assert_eq!(
19780                c.contratos().is_empty(),
19781                c.contratos.is_empty(),
19782                "Caixa::contratos().is_empty() must byte-equal \
19783                 self.contratos.is_empty() — a presence-bit drift would \
19784                 silently split the paired Caixa::declared_mesh_slots \
19785                 mesh declared-slot enumerator's presence probe from \
19786                 the peer Caixa::aplicacao_view typed-view composer's \
19787                 fold-in path",
19788            );
19789        }
19790    }
19791
19792    #[test]
19793    fn declared_mesh_slots_contratos_arm_routes_through_accessor() {
19794        // Composition pin: [`Caixa::declared_mesh_slots`]'s `:contratos`
19795        // presence-probe arm must key off [`Caixa::contratos`], not the
19796        // raw `!self.contratos.is_empty()` field-probe. Structurally: a
19797        // `Caixa { contratos: vec![WitContract { .. }], .. }` must push
19798        // `M3_AUTHOR_KEY_CONTRATOS` onto the declared-slot list (the
19799        // presence bit is non-empty, so the mesh kind-coherence gate
19800        // must surface the slot as "declared"), and a `Caixa {
19801        // contratos: vec![], .. }` must NOT push the label (the "author
19802        // omitted the slot entirely" arm — the empty-slice partition
19803        // the serde-default folds onto). The pair jointly pins the
19804        // accessor + declared-slot enumerator composition: any future
19805        // silent detour that had the accessor collapse
19806        // `[WitContract { .. }]` to `[]` (a `.filter(|c| c.de() !=
19807        // "__reserved__")` projection) would silently absorb the
19808        // "declared but degenerate" arm at the accessor boundary and
19809        // the [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
19810        // coherence gate would silently accept a struct-literal
19811        // `Caixa` carrying the drift.
19812        //
19813        // Peer of the sibling
19814        // `declared_servico_slots_upgrade_from_arm_routes_through_accessor`
19815        // (2a1f907),
19816        // `declared_supervisor_slots_children_arm_routes_through_accessor`
19817        // (c17b51e), and
19818        // `declared_mesh_slots_membros_arm_routes_through_accessor`
19819        // (0f26987) composition pins on the M2 `:upgrade-from` /
19820        // `:children` / M3 `:membros` composite-slice arms — same "the
19821        // enumerator gate must route through the substrate-primitive
19822        // typed dispatch" discipline extended onto the M3 `:contratos`
19823        // composite-slice arm, closing the M3 mesh-slot arm of the
19824        // declared-slot enumerator's routing invariant on the
19825        // composite-slice inputs.
19826        let c = caixa_aplicacao_with_contratos(vec![contrato_http_for_test(
19827            "cart", "catalog", "/items",
19828        )]);
19829        let slots = c.declared_mesh_slots();
19830        assert!(
19831            slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
19832            "declared_mesh_slots must push M3_AUTHOR_KEY_CONTRATOS when \
19833             `:contratos` is non-empty — the accessor and the enumerator \
19834             gate must route through the same substrate-primitive \
19835             typed dispatch on the outer :contratos presence bit (got \
19836             slots={slots:?})",
19837        );
19838        let c = caixa_aplicacao_with_contratos(vec![]);
19839        let slots = c.declared_mesh_slots();
19840        assert!(
19841            !slots.contains(&crate::render::M3_AUTHOR_KEY_CONTRATOS),
19842            "declared_mesh_slots must NOT push M3_AUTHOR_KEY_CONTRATOS \
19843             when `:contratos` is empty — the author-omitted arm must \
19844             route through the accessor's empty-slice return unchanged \
19845             (got slots={slots:?})",
19846        );
19847    }
19848
19849    #[test]
19850    fn aplicacao_view_contratos_arm_routes_through_accessor() {
19851        // Composition pin: [`Caixa::aplicacao_view`]'s per-`:contratos`
19852        // fold-in arm must key off [`Caixa::contratos`], not the raw
19853        // `self.contratos.clone()` field-clone. Structurally: a `Caixa
19854        // { kind: Aplicacao, contratos: vec![WitContract { de: "cart",
19855        // .. }, WitContract { de: "pricing", .. }], .. }` must fold the
19856        // per-edge list through the accessor into the typed
19857        // [`crate::AplicacaoSpec`] view's `contratos` slot verbatim —
19858        // every entry the accessor surfaces must land in the view's
19859        // `contratos` slot in the same order. The pair jointly pins
19860        // the accessor + view-composer composition: a future silent
19861        // detour that had the accessor shuffle or drop an edge would
19862        // silently split the paired declared-slot enumerator's
19863        // presence bit from the typed-view composer's edge-list, a
19864        // two-consumer split at the enumerator and the view composer
19865        // far from the source `caixa.lisp`.
19866        //
19867        // Peer of the sibling
19868        // `aplicacao_view_membros_arm_routes_through_accessor`
19869        // (0f26987) composition pin on the M3 `:membros` outer-
19870        // `&[Composite]` composite-slice arm, closing the aplicacao-
19871        // view composer's routing invariant on the composite-slice
19872        // inputs at the outer altitude.
19873        let c = caixa_aplicacao_with_contratos(vec![
19874            contrato_http_for_test("cart", "catalog", "/items"),
19875            contrato_http_for_test("cart", "pricing", "/price"),
19876        ]);
19877        let view = c
19878            .aplicacao_view()
19879            .expect("Aplicacao kind must produce an aplicacao_view");
19880        assert_eq!(
19881            view.contratos(),
19882            c.contratos(),
19883            "aplicacao_view must fold Caixa::contratos verbatim into \
19884             AplicacaoSpec::contratos — the accessor and the view \
19885             composer must route through the same substrate-primitive \
19886             typed dispatch on the outer :contratos slice (got view \
19887             contratos={:?}, expected {:?})",
19888            view.contratos(),
19889            c.contratos(),
19890        );
19891    }
19892
19893    #[test]
19894    fn contratos_projects_slice_by_borrow() {
19895        // The by-borrow pin: [`Caixa::contratos`] returns `&[WitContract]`
19896        // by borrow — the returned slice borrows the underlying
19897        // `Vec<WitContract>` storage of the `:contratos` slot and the
19898        // accessor must not clone the backing `Vec` on every call.
19899        // Peer of the sibling outer top-level [`Caixa`] `&[T]`-return
19900        // by-borrow pins (`autores_projects_slice_by_borrow` b5d813f,
19901        // `etiquetas_projects_slice_by_borrow` 78c7d3c,
19902        // `bibliotecas_projects_slice_by_borrow` 8a36c23,
19903        // `exe_projects_slice_by_borrow` 65d9527,
19904        // `servicos_projects_slice_by_borrow` 611f78b,
19905        // `deps_projects_slice_by_borrow` ad34b4e,
19906        // `deps_dev_projects_slice_by_borrow` f7fd81e,
19907        // `upgrade_from_projects_slice_by_borrow` 2a1f907,
19908        // `children_projects_slice_by_borrow` c17b51e,
19909        // `membros_projects_slice_by_borrow` 0f26987) on the sibling
19910        // outer top-level [`Caixa`] scalar-element and composite-
19911        // element `&[T]` axes — closes the outer-`Caixa` M3 mesh-slot
19912        // composite-element `&[Composite]` axis on the by-borrow pin:
19913        // the accessor's returned slice must borrow from `&self` (the
19914        // returned reference's lifetime is tied to `&self`), and
19915        // calling the accessor twice on the same [`Caixa`] must yield
19916        // slices that are pointer-equal (the underlying byte-buffer is
19917        // the storage `Vec`'s allocation, not a fresh copy) as well as
19918        // value-equal (idempotent, no side effects on `&self`).
19919        //
19920        // Pins against a future silent detour that returned an owned
19921        // `Vec<WitContract>` (which would type-check but silently clone
19922        // on every call), a `&Vec<WitContract>` return (which would
19923        // leak the backing `Vec`'s grow/push/reserve surface no
19924        // downstream consumer reaches for), or a one-arm-only accessor
19925        // that returned a saturating value on some sentinel input.
19926        for contratos in [
19927            vec![],
19928            vec![contrato_http_for_test("cart", "catalog", "/items")],
19929            vec![
19930                contrato_http_for_test("cart", "catalog", "/items"),
19931                contrato_http_for_test("cart", "pricing", "/price"),
19932            ],
19933        ] {
19934            let c = caixa_aplicacao_with_contratos(contratos.clone());
19935            let first = c.contratos();
19936            let second = c.contratos();
19937            assert_eq!(
19938                first, second,
19939                "Caixa::contratos must be idempotent — two successive \
19940                 calls on the same &self must return the same \
19941                 &[WitContract]",
19942            );
19943            assert_eq!(
19944                first.as_ptr(),
19945                second.as_ptr(),
19946                "Caixa::contratos must borrow the underlying \
19947                 Vec<WitContract> storage — two successive calls must \
19948                 return slices with the same backing pointer (a fresh \
19949                 Vec<WitContract> clone would change the pointer on \
19950                 every call)",
19951            );
19952            assert_eq!(
19953                first,
19954                contratos.as_slice(),
19955                "Caixa::contratos must return :contratos verbatim by \
19956                 borrow — got {first:?}, expected {contratos:?}",
19957            );
19958        }
19959    }
19960
19961    // ── drift-detection: Caixa top-level multi-word serde-derive-to-const identity ──
19962
19963    #[test]
19964    fn caixa_multi_word_serde_keys_match_lifted_top_level_key_consts() {
19965        // Load-bearing invariant: every multi-word top-level [`Caixa`]
19966        // serde-derived JSON key routes through a lifted `&'static str`
19967        // const. The Rust field names are `snake_case`
19968        // (`deps_dev` / `upgrade_from` / `max_restarts` /
19969        // `restart_window`); [`Caixa`]'s `#[serde(rename_all =
19970        // "camelCase")]` derive attribute maps each to the camelCase
19971        // byte-string the [`Caixa::to_lisp`] round-trip's
19972        // `serde_json::to_value(self)` step lands under before
19973        // `tatara_lisp::domain::json_to_sexp` re-projects the JSON keys
19974        // to the kebab-case `:deps-dev` / `:upgrade-from` /
19975        // `:max-restarts` / `:restart-window` author surface. Serialize
19976        // a fully-populated [`Caixa`] and pin that each canonical
19977        // byte-sequence appears verbatim in the JSON — a future
19978        // accidental `rename_all = "snake_case"` / `"kebab-case"` /
19979        // verbatim-field-name flip at the derive attribute (any of
19980        // which would silently break every [`Caixa::to_lisp`]
19981        // round-trip and the future M4 operator-side manifest ingest's
19982        // `Value::get(<key>)` navigation) surfaces here as a build-time
19983        // test failure at `manifest.rs`, not as an apply-time
19984        // `.get(<stale-canonical-const>)` returning `None` far from the
19985        // derive-attr drift's commit. Same discipline the sibling
19986        // `supervisor_spec_serde_keys_match_lifted_supervisor_key_consts`
19987        // (40cc4e5), `membro_serde_keys_match_lifted_membro_key_consts`
19988        // (ce80ca0), and `upgrade_from_entry_serde_keys_match_lifted_
19989        // m2_upgrade_from_key_consts` (36ffe65) pins established on the
19990        // sibling M2 supervision-tree, M3 [`Membro`] per-entry, and M2
19991        // [`UpgradeFromEntry`] per-entry axes — extended here to the
19992        // enclosing M0 [`Caixa`] top-level axis so the last of the four
19993        // multi-word top-level [`Caixa`] serde-derived JSON keys
19994        // (`depsDev`) joins the substrate's "one canonical byte-string
19995        // per typed serialized-key axis" discipline.
19996        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
19997        use crate::upgrade::{UpgradeFromEntry, UpgradeInstruction};
19998        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
19999        c.deps_dev = vec![Dep::simple("tatara-check", "^0.1")];
20000        c.upgrade_from = vec![UpgradeFromEntry {
20001            from: "0.0.1".into(),
20002            instructions: vec![UpgradeInstruction::Restart],
20003        }];
20004        c.estrategia = Some(RestartStrategy::OneForOne);
20005        c.max_restarts = Some(3);
20006        c.restart_window = Some("60s".into());
20007        c.children = vec![ChildSpec {
20008            caixa: "child".into(),
20009            versao: "^0.1".into(),
20010            restart: RestartPolicy::Permanent,
20011        }];
20012        let json = serde_json::to_string(&c).unwrap();
20013        for key in [
20014            crate::render::CAIXA_KEY_DEPS_DEV,
20015            crate::render::M2_KEY_UPGRADE_FROM,
20016            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20017            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20018        ] {
20019            let quoted = format!("\"{key}\"");
20020            assert!(
20021                json.contains(&quoted),
20022                "serialized Caixa must carry the lifted top-level \
20023                 multi-word byte-sequence {quoted} verbatim in the JSON \
20024                 emission (got: {json})",
20025            );
20026        }
20027    }
20028
20029    #[test]
20030    fn caixa_top_level_multi_word_key_consts_are_pairwise_distinct() {
20031        // Cross-axis drift-detection pin: a future collapse of the four
20032        // canonical [`Caixa`] top-level multi-word byte-strings onto the
20033        // same value (e.g. an accidental copy-paste flip of
20034        // [`crate::render::CAIXA_KEY_DEPS_DEV`] to also read
20035        // `"upgradeFrom"`) would silently reroute every downstream
20036        // `Value::get(<key>)` probe on one axis onto the sibling axis's
20037        // top-level entry and pass every propagation-probe test that
20038        // expected only the stale axis's value. Peer of the sibling
20039        // four-way distinct pin on the `SUPERVISOR_KEY_*` tetrad
20040        // (40cc4e5) and the two-way pin on `MEMBRO_KEY_*` (ce80ca0).
20041        let all = [
20042            crate::render::CAIXA_KEY_DEPS_DEV,
20043            crate::render::M2_KEY_UPGRADE_FROM,
20044            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20045            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20046        ];
20047        for (i, a) in all.iter().enumerate() {
20048            for b in all.iter().skip(i + 1) {
20049                assert_ne!(
20050                    a, b,
20051                    "Caixa top-level multi-word key consts must be \
20052                     pairwise-distinct canonical byte-sequences — got \
20053                     `{a}` == `{b}`",
20054                );
20055            }
20056        }
20057    }
20058
20059    #[test]
20060    fn caixa_top_level_multi_word_key_consts_are_lower_camel_case_shape() {
20061        // Shape-pin: every [`Caixa`] top-level multi-word key const must
20062        // be a lowerCamelCase byte-sequence (no `snake_case`
20063        // underscores, no `kebab-case` hyphens, no leading colon, no
20064        // `PascalCase` leading capital, no whitespace / dots) — the
20065        // canonical shape the `#[serde(rename_all = "camelCase")]`
20066        // derive produces on [`Caixa`]. A future flip to a
20067        // non-camelCase attribute at the derive surfaces both here
20068        // (this test fails on the stale-constant shape) and at
20069        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20070        // (that test fails on the mismatch between const and derive).
20071        // Peer with `membro_key_consts_are_lower_camel_case_shape`
20072        // (ce80ca0) and `supervisor_key_consts_are_lower_camel_case_shape`
20073        // (40cc4e5) on the sibling per-entry / supervisor-tree axes.
20074        for key in [
20075            crate::render::CAIXA_KEY_DEPS_DEV,
20076            crate::render::M2_KEY_UPGRADE_FROM,
20077            crate::render::SUPERVISOR_KEY_MAX_RESTARTS,
20078            crate::render::SUPERVISOR_KEY_RESTART_WINDOW,
20079        ] {
20080            assert!(
20081                !key.is_empty(),
20082                "Caixa top-level multi-word key const must be non-empty \
20083                 (got {key:?})"
20084            );
20085            let first = key.chars().next().unwrap();
20086            assert!(
20087                first.is_ascii_lowercase(),
20088                "Caixa top-level multi-word key const must lead with an \
20089                 ASCII-lowercase byte (got {key:?}, leads with {first:?})",
20090            );
20091            assert!(
20092                key.chars().all(|c| c.is_ascii_alphanumeric()),
20093                "Caixa top-level multi-word key const must be \
20094                 ASCII-alphanumeric only — no `_` / `-` / `:` / `.` / \
20095                 whitespace (got {key:?})",
20096            );
20097        }
20098    }
20099
20100    #[test]
20101    fn caixa_key_deps_dev_pins_canonical_camel_case_byte_string() {
20102        // Scalar-value pin: the byte-string the
20103        // [`crate::render::CAIXA_KEY_DEPS_DEV`] const resolves to,
20104        // asserted verbatim. A future rebrand (`depsDev` → `devDeps`
20105        // matching Cargo's verbatim `dev-dependencies` axis, `depsDev`
20106        // → `depsTest` matching a hypothetical per-test-target
20107        // vocabulary flip) lands as an edit to exactly one const AND
20108        // one derive attribute — the sibling
20109        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20110        // pin already ties the const to the derive attribute, so a
20111        // rebrand that touches only one side of the pair fails at
20112        // caixa-core build time. Same "scalar-value pin per const"
20113        // discipline the sibling
20114        // `m2_top_level_author_key_consts_pin_canonical_kebab_case_labels`
20115        // (f49c8b0) and `contrato_key_consts_pin_canonical_camel_case_labels`
20116        // (ca463a4) pins carry on the peer M2 / M3 top-level slot axes.
20117        assert_eq!(crate::render::CAIXA_KEY_DEPS_DEV, "depsDev");
20118    }
20119
20120    #[test]
20121    fn caixa_key_deps_pins_canonical_byte_string() {
20122        // Scalar-value pin: the byte-string the
20123        // [`crate::render::CAIXA_KEY_DEPS`] const resolves to, asserted
20124        // verbatim. Peer of `caixa_key_deps_dev_pins_canonical_camel_case_byte_string`
20125        // on the two-list dep-graph serialized-key axis — the sibling
20126        // pin covers the multi-word `deps_dev → depsDev` camelCase
20127        // arm, this pin covers the single-word `deps → deps` no-op arm
20128        // (the [`crate::Caixa::deps`] field name carries no `_`, so the
20129        // `#[serde(rename_all = "camelCase")]` derive is a no-op on this
20130        // axis and the emitted JSON key equals the source-side field
20131        // name byte-for-byte). A future [`crate::Caixa::deps`] field
20132        // rename (`deps` → `dependencies` matching Cargo's verbatim
20133        // `[dependencies]` axis, `deps` → `runtime_deps` matching a
20134        // hypothetical per-runtime-target vocabulary flip) OR an added
20135        // `#[serde(rename = "…")]` explicit override lands as an edit
20136        // to exactly one const AND one derive-attr / field name — the
20137        // sibling `caixa_deps_serde_key_matches_lifted_caixa_key_deps`
20138        // pin ties the const to the emitted JSON key, so a rebrand
20139        // that touches only one side of the pair fails at caixa-core
20140        // build time.
20141        assert_eq!(crate::render::CAIXA_KEY_DEPS, "deps");
20142    }
20143
20144    #[test]
20145    fn caixa_deps_serde_key_matches_lifted_caixa_key_deps() {
20146        // Load-bearing invariant on the single-word `deps` top-level
20147        // axis: the byte-string [`crate::render::CAIXA_KEY_DEPS`] pins
20148        // must appear verbatim in the JSON [`Caixa::to_lisp`]'s
20149        // `serde_json::to_value(self)` step emits. Serialize a
20150        // populated [`Caixa`] whose `:deps` slot carries at least one
20151        // entry (the `#[serde(default)]` attribute on the field emits
20152        // an empty `[]` even without members, but a non-empty vec
20153        // additionally covers the codec's per-`Dep`-entry emission
20154        // path) and pin that `"deps"` appears verbatim in the JSON
20155        // emission — a future accidental `rename_all = "snake_case"` /
20156        // `"kebab-case"` flip at the derive attribute (or an added
20157        // `#[serde(rename = "…")]` explicit override on the field, or
20158        // a Rust field rename) would break every [`Caixa::to_lisp`]
20159        // round-trip and the future M4 operator-side manifest ingest's
20160        // `Value::get(CAIXA_KEY_DEPS)` navigation — surfaces here as a
20161        // build-time test failure at `manifest.rs`, not as an
20162        // apply-time `.get(<stale-canonical-const>)` returning `None`
20163        // far from the drift's commit. Peer of the sibling
20164        // `caixa_multi_word_serde_keys_match_lifted_top_level_key_consts`
20165        // multi-word pin on the same M0 [`Caixa`] top-level
20166        // serialized-key axis, extended here to the single-word arm
20167        // the multi-word test's `rename_all = "camelCase"` sweep can't
20168        // reach (single-word `deps → deps` is a no-op the multi-word
20169        // pin's `\"depsDev\"` / `\"upgradeFrom\"` / `\"maxRestarts\"` /
20170        // `\"restartWindow\"` byte-scan can never observe).
20171        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20172        c.deps = vec![Dep::simple("caixa-core", "^0.1")];
20173        let json = serde_json::to_string(&c).unwrap();
20174        let quoted = format!("\"{}\"", crate::render::CAIXA_KEY_DEPS);
20175        assert!(
20176            json.contains(&quoted),
20177            "serialized Caixa must carry the lifted top-level `deps` \
20178             byte-sequence {quoted} verbatim in the JSON emission (got: \
20179             {json})",
20180        );
20181    }
20182
20183    #[test]
20184    fn caixa_dep_graph_two_list_key_consts_are_pairwise_distinct() {
20185        // Cross-axis drift-detection pin on the two-list dep-graph
20186        // renderer-side wire-key axis: a future collapse of the
20187        // canonical [`crate::render::CAIXA_KEY_DEPS`] /
20188        // [`crate::render::CAIXA_KEY_DEPS_DEV`] byte-strings onto the
20189        // same value (e.g. an accidental copy-paste flip of
20190        // `CAIXA_KEY_DEPS_DEV` to also read `"deps"`) would silently
20191        // reroute every downstream `Value::get(<key>)` probe on one
20192        // axis onto the sibling axis's dep-list and pass every
20193        // propagation-probe test that expected only the stale axis's
20194        // value — a dev-only dep would land in the runtime closure at
20195        // publish time, or a runtime dep would be excluded from the
20196        // published lacre. Peer of the sibling four-way distinct pin
20197        // on the top-level multi-word tetrad
20198        // (`caixa_top_level_multi_word_key_consts_are_pairwise_distinct`)
20199        // and the two-way pin on the sibling
20200        // [`DEP_AUTHOR_KEY_DEPS`] / [`DEP_AUTHOR_KEY_DEPS_DEV`]
20201        // author-facing arm (4da6fba's test), extended here to the
20202        // renderer-side wire-key arm of the same two-list dep-graph
20203        // axis so both halves of the "one canonical byte-string per
20204        // typed axis per (author, wire)" grid carry the same
20205        // distinct-ness discipline.
20206        assert_ne!(
20207            crate::render::CAIXA_KEY_DEPS,
20208            crate::render::CAIXA_KEY_DEPS_DEV,
20209            "CAIXA_KEY_DEPS and CAIXA_KEY_DEPS_DEV must be distinct \
20210             canonical byte-sequences on the two-list dep-graph \
20211             renderer-side wire-key axis"
20212        );
20213    }
20214
20215    // ── DepList / Caixa::push_dep pin ────────────────────────────────
20216    //
20217    // The compounding pin: the two-arm closed-set typed enum
20218    // [`crate::dep::DepList`] carries the runtime-closure `:deps`
20219    // (`Prod`) vs dev-only-closure `:deps-dev` (`Dev`) dispatch every
20220    // consumer of the top-level manifest's dep-mutation surface reads
20221    // through, and the typed dispatch [`Caixa::push_dep`] on the
20222    // substrate primitive folds the "select list → check within-list
20223    // dup → push" cascade onto one method call. Prior to this landing
20224    // the two axes lived across two `&'static str` constants
20225    // (`DEP_AUTHOR_KEY_DEPS`, `DEP_AUTHOR_KEY_DEPS_DEV`) with no closed-
20226    // set type carrying the pair; the `feira add` mutation site's
20227    // inline `if self.dev { &mut caixa.deps_dev } else { &mut
20228    // caixa.deps }` dispatch expressed no compile-time link back to
20229    // the substrate primitive, and a future third dep-list axis would
20230    // have silently split at every open-coded mutation site.
20231
20232    #[test]
20233    fn dep_list_as_str_routes_through_lifted_author_key_constants() {
20234        // Every arm returns the same `&'static str` the substrate's
20235        // canonical `DEP_AUTHOR_KEY_DEPS` / `DEP_AUTHOR_KEY_DEPS_DEV`
20236        // constants carry. A future rebrand on either constant reaches
20237        // the enum through one edit; a regression to inline literals
20238        // (e.g. `Prod => ":deps"`) would silently split the diagnostic
20239        // quotes from the wire-format constants every consumer routes
20240        // through and this pin flags it at build time.
20241        assert_eq!(
20242            crate::dep::DepList::Prod.as_str(),
20243            crate::render::DEP_AUTHOR_KEY_DEPS
20244        );
20245        assert_eq!(
20246            crate::dep::DepList::Dev.as_str(),
20247            crate::render::DEP_AUTHOR_KEY_DEPS_DEV
20248        );
20249    }
20250
20251    #[test]
20252    fn dep_list_display_routes_through_as_str() {
20253        // Same as-str-through-Display convergence discipline the
20254        // sibling closed-set typed enums carry — a `format!("{list}")`
20255        // call must land byte-for-byte on the accessor's return so a
20256        // future consumer that formats the enum for a diagnostic line
20257        // reaches the same wire-format constant the wire-format
20258        // producers do.
20259        assert_eq!(
20260            format!("{}", crate::dep::DepList::Prod),
20261            crate::dep::DepList::Prod.as_str()
20262        );
20263        assert_eq!(
20264            format!("{}", crate::dep::DepList::Dev),
20265            crate::dep::DepList::Dev.as_str()
20266        );
20267    }
20268
20269    #[test]
20270    fn dep_list_all_enumerates_every_variant_once() {
20271        // Exhaustive-iteration pin — every arm appears exactly once in
20272        // `ALL`, matching the closed set the compiler enforces on the
20273        // sibling `match self` arms. A future variant addition that
20274        // extends only one method's match without extending `ALL`
20275        // would silently drop the new arm from every consumer that
20276        // iterates the slice.
20277        let variants: &[crate::dep::DepList] = crate::dep::DepList::ALL;
20278        assert!(variants.contains(&crate::dep::DepList::Prod));
20279        assert!(variants.contains(&crate::dep::DepList::Dev));
20280        assert_eq!(variants.len(), 2);
20281    }
20282
20283    #[test]
20284    fn dep_list_from_wire_returns_prod_on_deps_wire_scalar() {
20285        // Reverse projection on the two-list dep-graph axis: the
20286        // author-surface wire tag the sibling `as_str` emitter walks
20287        // for `Prod` (`:deps` via `DEP_AUTHOR_KEY_DEPS`) parses back to
20288        // `Some(DepList::Prod)`. A regression that hand-rolled the
20289        // per-arm match without routing through the lifted
20290        // `DEP_AUTHOR_KEY_DEPS` const would silently disagree on any
20291        // future wire-tag rebrand and this pin flags it at build time.
20292        assert_eq!(
20293            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS),
20294            Some(crate::dep::DepList::Prod)
20295        );
20296    }
20297
20298    #[test]
20299    fn dep_list_from_wire_returns_dev_on_deps_dev_wire_scalar() {
20300        // Peer of the `Prod`-arm pin on the dev-only axis: the
20301        // author-surface wire tag the sibling `as_str` emitter walks
20302        // for `Dev` (`:deps-dev` via `DEP_AUTHOR_KEY_DEPS_DEV`) parses
20303        // back to `Some(DepList::Dev)`. Same drift-detection posture
20304        // as the peer arm — the sibling method `match` arms are
20305        // compiler-checked exhaustive so a future variant addition
20306        // trips at build time.
20307        assert_eq!(
20308            crate::dep::DepList::from_wire(crate::render::DEP_AUTHOR_KEY_DEPS_DEV),
20309            Some(crate::dep::DepList::Dev)
20310        );
20311    }
20312
20313    #[test]
20314    fn dep_list_from_wire_returns_none_on_unknown_wire_scalar() {
20315        // Every input outside the closed-set arm-string set the
20316        // sibling `as_str` emitter walks lands on the terminal `None`
20317        // fallback — no silent-accept surface. Sweeps a set of
20318        // plausibly-adjacent scalars (unprefixed wire form, PascalCase
20319        // rebrand candidates, foreign wire tags, empty string) so a
20320        // future variant addition that widened one wire form without
20321        // extending the emitter's arm-set would trip the sibling
20322        // round-trip pin below rather than silently accepting the new
20323        // form here.
20324        for candidate in [
20325            "",
20326            "deps",
20327            "deps-dev",
20328            ":deps ",
20329            ":Deps",
20330            ":DEPS",
20331            ":build-dep",
20332            ":tool-dep",
20333            "prod",
20334            "dev",
20335        ] {
20336            assert_eq!(
20337                crate::dep::DepList::from_wire(candidate),
20338                None,
20339                "from_wire({candidate:?}) must return None; every input outside \
20340                 the {{DEP_AUTHOR_KEY_DEPS, DEP_AUTHOR_KEY_DEPS_DEV}} accept-set \
20341                 the sibling as_str emitter walks lands on the terminal fallback",
20342            );
20343        }
20344    }
20345
20346    #[test]
20347    fn dep_list_round_trips_through_as_str_and_from_wire() {
20348        // Load-bearing round-trip pin: every arm the `ALL` iteration
20349        // exposes survives the `as_str` → `from_wire` composition
20350        // byte-for-byte. Same discipline the sibling closed-set enums
20351        // carry — `CaixaKind` /
20352        // `RestartStrategy` / `RestartPolicy` /
20353        // `PlacementStrategy` — extended onto the two-list dep-graph
20354        // axis. A future variant addition that extends `ALL` +
20355        // `as_str` without extending `from_wire` (or vice versa)
20356        // trips at build time on this iteration because the compiler
20357        // enforces exhaustiveness on the sibling `match self` arms.
20358        for &list in crate::dep::DepList::ALL {
20359            assert_eq!(
20360                crate::dep::DepList::from_wire(list.as_str()),
20361                Some(list),
20362                "DepList::from_wire(as_str({list:?})) must round-trip to Some({list:?}) — \
20363                 a silent split between the forward emitter and the reverse parser \
20364                 would drift the two halves of the two-list dep-graph axis's typed dispatch",
20365            );
20366        }
20367    }
20368
20369    #[test]
20370    fn push_dep_routes_to_deps_slot_on_prod_arm() {
20371        // The `Prod` arm dispatches to the runtime-closure `:deps`
20372        // slot every downstream lacre-pipeline consumer resolves at
20373        // build time. A future arm that regressed to inline `&mut
20374        // self.deps_dev` on the `Prod` path would silently reroute
20375        // every runtime dep into the dev-only closure at publish time
20376        // — this pin refuses that regression.
20377        let src = Caixa::template("host");
20378        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20379        let before_deps = caixa.deps().len();
20380        let before_deps_dev = caixa.deps_dev().len();
20381        let dep = Dep {
20382            nome: "caixa-teia".to_string(),
20383            versao: "^0.1".to_string(),
20384            fonte: None,
20385            opcional: false,
20386            caracteristicas: Vec::new(),
20387        };
20388        caixa
20389            .push_dep(crate::dep::DepList::Prod, dep)
20390            .expect("first push into :deps succeeds");
20391        assert_eq!(caixa.deps().len(), before_deps + 1);
20392        assert_eq!(caixa.deps_dev().len(), before_deps_dev);
20393        assert_eq!(caixa.deps().last().unwrap().nome(), "caixa-teia");
20394    }
20395
20396    #[test]
20397    fn push_dep_routes_to_deps_dev_slot_on_dev_arm() {
20398        // Peer of the sibling `Prod`-arm dispatch pin — the `Dev` arm
20399        // must dispatch to the dev-only-closure `:deps-dev` slot every
20400        // downstream test-facing artifact resolver reads. A future
20401        // regression that inverted the two arms would silently route
20402        // every dev-only dep into the runtime closure at publish time
20403        // and this pin catches it before the drift ships.
20404        let src = Caixa::template("host");
20405        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20406        let dep = Dep {
20407            nome: "tatara-check".to_string(),
20408            versao: "*".to_string(),
20409            fonte: None,
20410            opcional: false,
20411            caracteristicas: Vec::new(),
20412        };
20413        caixa
20414            .push_dep(crate::dep::DepList::Dev, dep)
20415            .expect("first push into :deps-dev succeeds");
20416        assert!(caixa.deps().is_empty());
20417        assert_eq!(caixa.deps_dev().len(), 1);
20418        assert_eq!(caixa.deps_dev().last().unwrap().nome(), "tatara-check");
20419    }
20420
20421    #[test]
20422    fn push_dep_refuses_within_list_duplicate_nome_with_typed_error() {
20423        // Within-list dup check routes through the canonical
20424        // [`DepError::DuplicateNome`] carrier — the substrate's typed
20425        // diagnostic for the same axis [`Caixa::validate_deps`]'s
20426        // parse-time [`crate::render::insert_first_seen`] walk raises
20427        // on. Prior to the lift the mutation site's inline
20428        // `bail!("dep '{}' already declared", …)` string-diagnostic
20429        // path expressed no through-line back to the typed error;
20430        // routing every dep-list refusal through one carrier means an
20431        // author reading a `feira add` refusal and a `feira build`
20432        // refusal reaches for the same corrective surface without
20433        // switching diagnostic idioms.
20434        let src = Caixa::template("host");
20435        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20436        let dep = Dep {
20437            nome: "caixa-teia".to_string(),
20438            versao: "^0.1".to_string(),
20439            fonte: None,
20440            opcional: false,
20441            caracteristicas: Vec::new(),
20442        };
20443        caixa
20444            .push_dep(crate::dep::DepList::Prod, dep.clone())
20445            .expect("first push succeeds");
20446        let dup = Dep {
20447            nome: "caixa-teia".to_string(),
20448            versao: "^0.2".to_string(),
20449            fonte: None,
20450            opcional: false,
20451            caracteristicas: Vec::new(),
20452        };
20453        let err = caixa
20454            .push_dep(crate::dep::DepList::Prod, dup)
20455            .expect_err("second push with same :nome refuses");
20456        assert_eq!(
20457            err,
20458            DepError::DuplicateNome {
20459                nome: "caixa-teia".to_string(),
20460                list: crate::render::DEP_AUTHOR_KEY_DEPS,
20461            }
20462        );
20463        // The refused mutation must not corrupt the target list —
20464        // exactly one entry lives past the refusal, matching the
20465        // canonical single-source-of-truth invariant `Caixa::deps()`
20466        // carries.
20467        assert_eq!(caixa.deps().len(), 1);
20468    }
20469
20470    #[test]
20471    fn push_dep_refuses_dup_on_dev_list_arm_names_deps_dev_key() {
20472        // Peer of the sibling `Prod`-arm dup-refusal pin — the `Dev`
20473        // arm's refusal must carry `DEP_AUTHOR_KEY_DEPS_DEV` in the
20474        // `list` payload so a future author reading the refusal grep's
20475        // for the correct `:deps-dev` block in their `caixa.lisp`,
20476        // not the sibling `:deps` block the runtime closure resolves.
20477        let src = Caixa::template("host");
20478        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20479        let dep = Dep {
20480            nome: "tatara-check".to_string(),
20481            versao: "*".to_string(),
20482            fonte: None,
20483            opcional: false,
20484            caracteristicas: Vec::new(),
20485        };
20486        caixa
20487            .push_dep(crate::dep::DepList::Dev, dep.clone())
20488            .expect("first push succeeds");
20489        let err = caixa
20490            .push_dep(crate::dep::DepList::Dev, dep)
20491            .expect_err("second push with same :nome refuses");
20492        assert!(matches!(
20493            err,
20494            DepError::DuplicateNome {
20495                ref nome,
20496                list,
20497            } if nome == "tatara-check"
20498                && list == crate::render::DEP_AUTHOR_KEY_DEPS_DEV
20499        ));
20500    }
20501
20502    #[test]
20503    fn push_dep_allows_same_nome_across_prod_and_dev_lists() {
20504        // The within-list dup check is scoped to the target arm — a
20505        // caixa may legitimately carry the same `:nome` under both
20506        // `:deps` and `:deps-dev` (though the substrate's peer
20507        // [`crate::Caixa::validate_deps`] walk still refuses the
20508        // shape at parse time; the mutation-site refusal is scoped to
20509        // the mutation-site's list to match the peer parse-time
20510        // per-list [`crate::render::insert_first_seen`] discipline).
20511        // The two arms hold independent seen-sets.
20512        let src = Caixa::template("host");
20513        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20514        let dep_prod = Dep {
20515            nome: "shared".to_string(),
20516            versao: "^0.1".to_string(),
20517            fonte: None,
20518            opcional: false,
20519            caracteristicas: Vec::new(),
20520        };
20521        let dep_dev = Dep {
20522            nome: "shared".to_string(),
20523            versao: "*".to_string(),
20524            fonte: None,
20525            opcional: false,
20526            caracteristicas: Vec::new(),
20527        };
20528        caixa
20529            .push_dep(crate::dep::DepList::Prod, dep_prod)
20530            .expect("push into :deps succeeds");
20531        caixa
20532            .push_dep(crate::dep::DepList::Dev, dep_dev)
20533            .expect("push same :nome into :deps-dev succeeds");
20534        assert_eq!(caixa.deps().len(), 1);
20535        assert_eq!(caixa.deps_dev().len(), 1);
20536    }
20537
20538    #[test]
20539    fn deps_of_prod_returns_the_deps_slot_verbatim() {
20540        // The `Prod` arm of the typed-dispatch [`Caixa::deps_of`] read
20541        // accessor must project onto the runtime-closure `:deps` slot —
20542        // element-equal and length-equal to the sibling per-slot
20543        // [`Caixa::deps`] accessor's return over every per-caixa fixture.
20544        // A future arm that regressed to `self.deps_dev()` on the `Prod`
20545        // path would silently reroute every downstream typed-dispatch
20546        // walker (the [`Caixa::validate_deps`] per-list
20547        // [`crate::render::insert_first_seen`] dedup walk, any future
20548        // per-axis-parametrised consumer) into the sibling dev-only
20549        // closure and this pin refuses that regression.
20550        let src = Caixa::template("host");
20551        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20552        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
20553        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 0);
20554        let dep = Dep {
20555            nome: "caixa-teia".to_string(),
20556            versao: "^0.1".to_string(),
20557            fonte: None,
20558            opcional: false,
20559            caracteristicas: Vec::new(),
20560        };
20561        caixa
20562            .push_dep(crate::dep::DepList::Prod, dep.clone())
20563            .expect("push into :deps succeeds");
20564        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod), caixa.deps());
20565        assert_eq!(caixa.deps_of(crate::dep::DepList::Prod).len(), 1);
20566        assert_eq!(
20567            caixa.deps_of(crate::dep::DepList::Prod)[0].nome(),
20568            "caixa-teia"
20569        );
20570    }
20571
20572    #[test]
20573    fn deps_of_dev_returns_the_deps_dev_slot_verbatim() {
20574        // Peer of the sibling `Prod`-arm pin — the `Dev` arm of
20575        // [`Caixa::deps_of`] must project onto the dev-only-closure
20576        // `:deps-dev` slot, element-equal and length-equal to the
20577        // sibling per-slot [`Caixa::deps_dev`] accessor's return. A
20578        // future regression that inverted the two arms would silently
20579        // route every dev-list walker onto the runtime closure and this
20580        // pin catches it before the drift ships.
20581        let src = Caixa::template("host");
20582        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20583        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
20584        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 0);
20585        let dep = Dep {
20586            nome: "tatara-check".to_string(),
20587            versao: "*".to_string(),
20588            fonte: None,
20589            opcional: false,
20590            caracteristicas: Vec::new(),
20591        };
20592        caixa
20593            .push_dep(crate::dep::DepList::Dev, dep)
20594            .expect("push into :deps-dev succeeds");
20595        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev), caixa.deps_dev());
20596        assert_eq!(caixa.deps_of(crate::dep::DepList::Dev).len(), 1);
20597        assert_eq!(
20598            caixa.deps_of(crate::dep::DepList::Dev)[0].nome(),
20599            "tatara-check"
20600        );
20601    }
20602
20603    #[test]
20604    fn deps_of_exhaustive_over_dep_list_all_covers_the_two_slots() {
20605        // Composition pin: iterating [`crate::dep::DepList::ALL`] through
20606        // [`Caixa::deps_of`] must land on the same two-slot partition the
20607        // per-slot [`Caixa::deps`] / [`Caixa::deps_dev`] accessors
20608        // expose — the canonical dispatch a future per-axis-parametrised
20609        // walker (a future `feira app graph` per-list dep summary, a
20610        // future M4 per-cluster dev-closure-audit overlay the CR
20611        // materializer resolves per-CR) reads through. Prior to the
20612        // lift the two-block iteration lived open-coded at every walker,
20613        // so a future third dep-list axis (`:deps-build`, per CAIXA-SDLC
20614        // §I) would have had to grow a third block at every consumer.
20615        // A regression that dropped the `Dev` arm from `ALL` would flip
20616        // the collected pairs to `[(":deps", &[])]` alone and this pin
20617        // refuses that shape.
20618        let src = Caixa::template("host");
20619        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20620        let prod_dep = Dep {
20621            nome: "caixa-teia".to_string(),
20622            versao: "^0.1".to_string(),
20623            fonte: None,
20624            opcional: false,
20625            caracteristicas: Vec::new(),
20626        };
20627        let dev_dep = Dep {
20628            nome: "tatara-check".to_string(),
20629            versao: "*".to_string(),
20630            fonte: None,
20631            opcional: false,
20632            caracteristicas: Vec::new(),
20633        };
20634        caixa
20635            .push_dep(crate::dep::DepList::Prod, prod_dep)
20636            .expect("push into :deps succeeds");
20637        caixa
20638            .push_dep(crate::dep::DepList::Dev, dev_dep)
20639            .expect("push into :deps-dev succeeds");
20640        let collected: Vec<(&'static str, usize, &str)> = crate::dep::DepList::ALL
20641            .iter()
20642            .map(|&list| {
20643                let slice = caixa.deps_of(list);
20644                (list.as_str(), slice.len(), slice[0].nome())
20645            })
20646            .collect();
20647        assert_eq!(
20648            collected,
20649            vec![
20650                (crate::render::DEP_AUTHOR_KEY_DEPS, 1, "caixa-teia"),
20651                (crate::render::DEP_AUTHOR_KEY_DEPS_DEV, 1, "tatara-check"),
20652            ]
20653        );
20654    }
20655
20656    #[test]
20657    fn caixa_deps_of_is_const_fn() {
20658        // Fail-before-pass-after pin on [`Caixa::deps_of`]'s
20659        // `const`-eval-surface posture. The typed-dispatch read
20660        // accessor forwards through the sibling `pub const fn`
20661        // [`Caixa::deps`] / [`Caixa::deps_dev`] per-slot slice
20662        // accessors on the two [`crate::dep::DepList`] enum arms —
20663        // every operator in the body is already `const`-callable
20664        // (`DepList` is a plain `#[derive(Copy)]` closed-set
20665        // discriminator so the `match` arms are const-evaluable, and
20666        // each arm dispatches through the sibling `pub const fn`
20667        // slice accessor). Any future accidental downgrade to
20668        // non-`const` fails the `deps_of_via_const_fn` wrapper below
20669        // at caixa-core build time with E0015 (`cannot call non-const
20670        // method`), strictly stronger than a runtime `assert!` and
20671        // side-stepping the destructor-in-const restriction the
20672        // `Caixa` fixture's owning `String` / `Vec<Dep>` carriers
20673        // rule out on the direct-`const _: () = assert!(...)`
20674        // residence.
20675        //
20676        // Peer of the sibling outer-`Caixa` accessor family pins
20677        // ([`caixa_outer_string_slice_return_accessor_family_is_const_fn`]
20678        // on the `&[String]` universal-axis surface,
20679        // [`caixa_outer_composite_slice_return_accessor_family_is_const_fn`]
20680        // on the outer `&[T]` composite-slice surface,
20681        // [`caixa_outer_option_composite_reference_return_accessor_family_is_const_fn`]
20682        // on the outer `Option<&Composite>` surface) — this pin
20683        // extends the `const`-eval-surface discipline onto the outer-
20684        // `Caixa` typed-dispatch read surface on the [`DepList`]-keyed
20685        // dep-list axis, closing the outer-`Caixa` accessor family's
20686        // last unlifted `pub fn` on the read side.
20687        const fn deps_of_via_const_fn(c: &Caixa, list: crate::dep::DepList) -> &[Dep] {
20688            c.deps_of(list)
20689        }
20690        let src = Caixa::template("host");
20691        let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20692        // Empty-list arm: both `Prod` and `Dev` degenerate to the
20693        // empty slice with no silent `None` collapse — the
20694        // `#[serde(default)]` `Vec::new()` fold every `defcaixa` form
20695        // that omits the slot lands on.
20696        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod).is_empty());
20697        assert!(deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev).is_empty());
20698        assert_eq!(
20699            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
20700            caixa.deps()
20701        );
20702        assert_eq!(
20703            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
20704            caixa.deps_dev()
20705        );
20706        // Populated arms: each list carries its own entry, and the
20707        // wrapper / direct dispatches agree byte-for-byte on the
20708        // slice-view under both non-empty arms.
20709        let prod_dep = Dep {
20710            nome: "caixa-teia".to_string(),
20711            versao: "^0.1".to_string(),
20712            fonte: None,
20713            opcional: false,
20714            caracteristicas: Vec::new(),
20715        };
20716        let dev_dep = Dep {
20717            nome: "tatara-check".to_string(),
20718            versao: "*".to_string(),
20719            fonte: None,
20720            opcional: false,
20721            caracteristicas: Vec::new(),
20722        };
20723        caixa
20724            .push_dep(crate::dep::DepList::Prod, prod_dep)
20725            .expect("push into :deps succeeds");
20726        caixa
20727            .push_dep(crate::dep::DepList::Dev, dev_dep)
20728            .expect("push into :deps-dev succeeds");
20729        assert_eq!(
20730            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod),
20731            caixa.deps()
20732        );
20733        assert_eq!(
20734            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev),
20735            caixa.deps_dev()
20736        );
20737        assert_eq!(
20738            deps_of_via_const_fn(&caixa, crate::dep::DepList::Prod)[0].nome(),
20739            "caixa-teia"
20740        );
20741        assert_eq!(
20742            deps_of_via_const_fn(&caixa, crate::dep::DepList::Dev)[0].nome(),
20743            "tatara-check"
20744        );
20745    }
20746
20747    #[test]
20748    fn validate_deps_iterates_through_dep_list_all_via_deps_of() {
20749        // Composition pin: the [`Caixa::validate_deps`] parse-time gate
20750        // must route its per-list [`crate::render::insert_first_seen`]
20751        // dedup walk through [`Caixa::deps_of`] + [`crate::dep::DepList::ALL`]
20752        // rather than the pre-lift open-coded two-block iteration over
20753        // `self.deps()` + `self.deps_dev()`. A regression that dropped
20754        // one arm (e.g. hand-inlining `self.deps()` alone) would silently
20755        // stop refusing within-list dups on the sibling arm; a
20756        // regression that flipped the arm-to-list-key mapping
20757        // (`Dev => DEP_AUTHOR_KEY_DEPS`) would silently mislabel the
20758        // diagnostic surface. Both drifts surface here through a paired
20759        // duplicate-name refusal per arm plus an offending-list-key
20760        // check on the emitted [`DepError::DuplicateNome`] carrier.
20761        for &list in crate::dep::DepList::ALL {
20762            let src = Caixa::template("host");
20763            let mut caixa = Caixa::from_lisp(&src).expect("template parses");
20764            let dup = Dep {
20765                nome: "twin".to_string(),
20766                versao: "^0.1".to_string(),
20767                fonte: None,
20768                opcional: false,
20769                caracteristicas: Vec::new(),
20770            };
20771            match list {
20772                crate::dep::DepList::Prod => {
20773                    caixa.deps.push(dup.clone());
20774                    caixa.deps.push(dup);
20775                }
20776                crate::dep::DepList::Dev => {
20777                    caixa.deps_dev.push(dup.clone());
20778                    caixa.deps_dev.push(dup);
20779                }
20780            }
20781            let err = caixa
20782                .validate_deps()
20783                .expect_err("within-list duplicate :nome must refuse");
20784            assert_eq!(
20785                err,
20786                DepError::DuplicateNome {
20787                    nome: "twin".to_string(),
20788                    list: list.as_str(),
20789                },
20790                "validate_deps on {list} arm must emit \
20791                 DepError::DuplicateNome carrying the arm's own \
20792                 as_str() diagnostic — the arm-to-list-key mapping \
20793                 flowed through DepList::ALL + Caixa::deps_of"
20794            );
20795        }
20796    }
20797
20798    #[test]
20799    fn caixa_licenca_default_pins_canonical_mit_byte() {
20800        // Bridge-arm pin: [`CAIXA_LICENCA_DEFAULT`] resolves to the
20801        // canonical SPDX-`"MIT"` byte today, the same license expression
20802        // every peer substrate-side consumer of the author-omitted
20803        // `:licenca` slot ([`caixa-helm`]'s `build_readme` fallback arm at
20804        // `caixa-helm/src/lib.rs`, the future M4
20805        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-CR
20806        // `Chart.yaml annotations["artifacthub.io/license"]` emitter this
20807        // crate's [`Caixa::validate_licenca`] docstring roadmap already
20808        // names as the second consumer) fills into its per-consumer
20809        // README/annotation emit site. Pin the literal here (peer with the
20810        // [`crate::version::DEFAULT_PUBLISH_TAG_PREFIX`] /
20811        // [`crate::version::DEFAULT_GIT_REMOTE`] /
20812        // [`crate::version::DEFAULT_PLEME_GIT_ORG`] canonical-literal pins
20813        // on the sibling lifted-constant surfaces) so a future
20814        // substrate-side license-fallback rebrand surfaces here as a
20815        // coordinated edit-point: the sibling caixa-helm
20816        // `build_readme_license_line_routes_through_lifted_caixa_licenca_default`
20817        // pinning test already pins the equality at the renderer-emit
20818        // axis; this pin closes the second coordinate of the pair by
20819        // anchoring the lifted constant's current byte to the canonical
20820        // CAIXA-SDLC §I license scaffold's documented shape.
20821        assert_eq!(CAIXA_LICENCA_DEFAULT, "MIT");
20822    }
20823
20824    // ── Caixa::validate_upgrade_from — compound per-Caixa entry gate on ──
20825    // ── the M2 `:upgrade-from` slot: folds the three top-level        ──
20826    // ── `crate::upgrade` validators (per-entry + cross-entry           ──
20827    // ── duplicate-`:from`, cross-slot `:from < :versao` precedence,   ──
20828    // ── cross-slot `:state-change` ↔ `:on-state-change` composition)  ──
20829    // ── onto one substrate primitive. Byte-for-byte equivalent to the ──
20830    // ── pre-fold three-block cascade at                               ──
20831    // ── `crate::layout::StandardLayout::verify` under the same        ──
20832    // ── canonical dispatch order.                                     ──
20833
20834    #[test]
20835    fn validate_upgrade_from_folds_per_entry_arm_matches_gate() {
20836        // Fail-before-pass-after per-arm equivalence pin on the
20837        // per-entry + cross-entry axis: a fixture whose `:upgrade-from`
20838        // carries a per-entry-invalid `:from` (git-tag shape `"v0.1.0"`,
20839        // which `semver::Version::parse` rejects) surfaces the same
20840        // [`crate::UpgradeError`] through the compound gate
20841        // [`Caixa::validate_upgrade_from`] and the standalone per-entry
20842        // gate [`crate::upgrade::validate_upgrade_from`] on the same
20843        // [`Caixa::upgrade_from`] slice. Pins the fold — a silent
20844        // regression that de-folded the per-entry arm would surface here
20845        // as a mismatch between the two dispatches. Sibling in shape to
20846        // the peer per-slot-≡-standalone equivalence pins the
20847        // [`crate::AplicacaoSpec::validate_contratos`] /
20848        // [`crate::MeshPolicy::validate`] /
20849        // [`crate::SupervisorSpec::validate_children`] compound gates
20850        // each carry on their axes.
20851        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20852        c.upgrade_from = vec![crate::UpgradeFromEntry {
20853            from: "v0.1.0".into(),
20854            instructions: vec![crate::UpgradeInstruction::Restart],
20855        }];
20856        let via_method = c.validate_upgrade_from().unwrap_err();
20857        let via_standalone = crate::upgrade::validate_upgrade_from(c.upgrade_from()).unwrap_err();
20858        assert_eq!(
20859            via_method, via_standalone,
20860            "Caixa::validate_upgrade_from must surface the per-entry \
20861             axis's diagnostic byte-equal to the standalone \
20862             `crate::upgrade::validate_upgrade_from` on the same \
20863             upgrade_from() slice"
20864        );
20865        assert!(
20866            matches!(
20867                via_method,
20868                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.1.0"
20869            ),
20870            "expected FromInvalid on the git-tag-shape `:from`, got {via_method:?}"
20871        );
20872    }
20873
20874    #[test]
20875    fn validate_upgrade_from_folds_versao_arm_matches_gate() {
20876        // Per-arm equivalence pin on the cross-slot `:from ↔ :versao`
20877        // precedence axis: a fixture with a well-formed `:from` (so the
20878        // per-entry arm passes) whose parsed semver is >= the caixa's
20879        // `:versao` under SemVer-2 precedence surfaces the same
20880        // [`crate::UpgradeError::FromNotBeforeVersao`] through both the
20881        // compound gate and the standalone
20882        // [`crate::upgrade::validate_upgrade_from_against_versao`] gate
20883        // keyed off the same `(upgrade_from, versao)` pair. Pins the
20884        // fold's second arm — reaching this arm through the compound
20885        // gate requires the per-entry arm to pass first, which itself
20886        // pins the per-arm cross-arm ordering.
20887        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20888        c.versao = "0.1.0".into();
20889        c.upgrade_from = vec![crate::UpgradeFromEntry {
20890            from: "0.2.0".into(),
20891            instructions: vec![crate::UpgradeInstruction::Restart],
20892        }];
20893        let via_method = c.validate_upgrade_from().unwrap_err();
20894        let via_standalone =
20895            crate::upgrade::validate_upgrade_from_against_versao(c.upgrade_from(), c.versao())
20896                .unwrap_err();
20897        assert_eq!(
20898            via_method, via_standalone,
20899            "Caixa::validate_upgrade_from must surface the \
20900             `:from >= :versao` diagnostic byte-equal to the standalone \
20901             `crate::upgrade::validate_upgrade_from_against_versao` on \
20902             the same (upgrade_from, versao) pair"
20903        );
20904        assert!(
20905            matches!(
20906                via_method,
20907                crate::UpgradeError::FromNotBeforeVersao { ref from, ref versao }
20908                    if from == "0.2.0" && versao == "0.1.0"
20909            ),
20910            "expected FromNotBeforeVersao carrying the offending pair, got {via_method:?}"
20911        );
20912    }
20913
20914    #[test]
20915    fn validate_upgrade_from_folds_behavior_arm_matches_gate() {
20916        // Per-arm equivalence pin on the cross-slot `:state-change ↔
20917        // :on-state-change` composition axis: a fixture with a
20918        // well-formed `:from` strictly less than `:versao` (so the
20919        // per-entry and versao arms both pass) whose `:instructions`
20920        // list carries a `(:state-change …)` instruction with no
20921        // `:behavior :on-state-change` callback declared surfaces the
20922        // same [`crate::UpgradeError::StateChangeWithoutOnStateChangeCallback`]
20923        // through both the compound gate and the standalone
20924        // [`crate::upgrade::validate_upgrade_from_against_behavior`]
20925        // gate keyed off the same `(upgrade_from, behavior)` pair.
20926        // Reaching this arm through the compound gate requires both
20927        // prior arms to pass first — the ordering pin below pins the
20928        // per-arm dispatch order explicitly.
20929        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20930        c.versao = "0.2.0".into();
20931        c.behavior = None;
20932        c.upgrade_from = vec![crate::UpgradeFromEntry {
20933            from: "0.1.0".into(),
20934            instructions: vec![
20935                crate::UpgradeInstruction::LoadModule {
20936                    module: "demo".into(),
20937                },
20938                crate::UpgradeInstruction::StateChange {
20939                    script: std::path::PathBuf::from("lib/m.lisp"),
20940                },
20941                crate::UpgradeInstruction::SoftPurge {
20942                    module: "demo-old".into(),
20943                },
20944            ],
20945        }];
20946        let via_method = c.validate_upgrade_from().unwrap_err();
20947        let via_standalone =
20948            crate::upgrade::validate_upgrade_from_against_behavior(c.upgrade_from(), c.behavior())
20949                .unwrap_err();
20950        assert_eq!(
20951            via_method, via_standalone,
20952            "Caixa::validate_upgrade_from must surface the \
20953             `:state-change` ↔ `:on-state-change` composition \
20954             diagnostic byte-equal to the standalone \
20955             `crate::upgrade::validate_upgrade_from_against_behavior` \
20956             on the same (upgrade_from, behavior) pair"
20957        );
20958        assert!(
20959            matches!(
20960                via_method,
20961                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback {
20962                    ref from,
20963                    ref script,
20964                } if from == "0.1.0" && script == &std::path::PathBuf::from("lib/m.lisp")
20965            ),
20966            "expected StateChangeWithoutOnStateChangeCallback carrying \
20967             the offending (from, script) pair, got {via_method:?}"
20968        );
20969    }
20970
20971    #[test]
20972    fn validate_upgrade_from_per_entry_arm_fires_before_versao_arm() {
20973        // Cross-arm ordering pin between the first two arms of the
20974        // fold: a fixture carrying BOTH a per-entry-invalid `:from`
20975        // (`"v0.0.5"` — git-tag shape rejected by
20976        // [`crate::upgrade::validate_upgrade_from`]) AND a would-be
20977        // versao-precedence violation on a second entry (`"0.2.0" >=
20978        // :versao "0.1.0"`) surfaces the per-entry diagnostic first
20979        // through the compound gate. Sanity assertion: the second
20980        // entry alone under the same `:versao` trips the versao arm
20981        // on its own via the standalone
20982        // [`crate::upgrade::validate_upgrade_from_against_versao`], so
20983        // the per-entry-first surfacing is a real ordering property,
20984        // not a case where the versao arm silently accepts the
20985        // fixture. Pins the pre-fold layout wire-up's canonical
20986        // dispatch order (per-entry → versao → behavior) as a
20987        // property of the substrate primitive rather than a
20988        // convention of the layout call site.
20989        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
20990        c.versao = "0.1.0".into();
20991        c.upgrade_from = vec![
20992            crate::UpgradeFromEntry {
20993                from: "v0.0.5".into(),
20994                instructions: vec![crate::UpgradeInstruction::Restart],
20995            },
20996            crate::UpgradeFromEntry {
20997                from: "0.2.0".into(),
20998                instructions: vec![crate::UpgradeInstruction::Restart],
20999            },
21000        ];
21001        let err = c.validate_upgrade_from().unwrap_err();
21002        assert!(
21003            matches!(
21004                err,
21005                crate::UpgradeError::FromInvalid { ref from, .. } if from == "v0.0.5"
21006            ),
21007            "per-entry arm must fire before versao arm — expected \
21008             FromInvalid on `v0.0.5`, got {err:?}"
21009        );
21010        // Sanity: the versao-violating second entry alone under the
21011        // same `:versao` trips the versao arm on its own — proves the
21012        // per-entry-first surfacing above is a real ordering property.
21013        let sanity = crate::upgrade::validate_upgrade_from_against_versao(
21014            &[crate::UpgradeFromEntry {
21015                from: "0.2.0".into(),
21016                instructions: vec![crate::UpgradeInstruction::Restart],
21017            }],
21018            "0.1.0",
21019        )
21020        .unwrap_err();
21021        assert!(
21022            matches!(sanity, crate::UpgradeError::FromNotBeforeVersao { .. }),
21023            "sanity: the versao-violating fixture alone must trip the \
21024             versao arm — got {sanity:?}"
21025        );
21026    }
21027
21028    #[test]
21029    fn validate_upgrade_from_versao_arm_fires_before_behavior_arm() {
21030        // Cross-arm ordering pin between the second and third arms of
21031        // the fold: a fixture carrying BOTH a versao-precedence
21032        // violation (`:from "0.2.0" >= :versao "0.1.0"`) AND a
21033        // would-be missing-callback violation (a `(:state-change …)`
21034        // instruction with no `:behavior :on-state-change`) surfaces
21035        // the versao diagnostic first through the compound gate.
21036        // Sanity assertion: the missing-callback fixture alone (with
21037        // the versao-precedence violation removed by bumping
21038        // `:versao` past `:from`) trips the behavior arm on its own
21039        // via the standalone
21040        // [`crate::upgrade::validate_upgrade_from_against_behavior`],
21041        // so the versao-first surfacing is a real ordering property,
21042        // not a case where the behavior arm silently accepts the
21043        // fixture.
21044        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21045        c.versao = "0.1.0".into();
21046        c.behavior = None;
21047        c.upgrade_from = vec![crate::UpgradeFromEntry {
21048            from: "0.2.0".into(),
21049            instructions: vec![
21050                crate::UpgradeInstruction::LoadModule {
21051                    module: "demo".into(),
21052                },
21053                crate::UpgradeInstruction::StateChange {
21054                    script: std::path::PathBuf::from("lib/m.lisp"),
21055                },
21056            ],
21057        }];
21058        let err = c.validate_upgrade_from().unwrap_err();
21059        assert!(
21060            matches!(
21061                err,
21062                crate::UpgradeError::FromNotBeforeVersao { ref from, .. } if from == "0.2.0"
21063            ),
21064            "versao arm must fire before behavior arm — expected \
21065             FromNotBeforeVersao on `0.2.0`, got {err:?}"
21066        );
21067        // Sanity: the same instructions under a `:versao` that
21068        // accepts the `:from` (so the versao arm passes) trips the
21069        // behavior arm — proves the versao-first surfacing above is a
21070        // real ordering property.
21071        let sanity = crate::upgrade::validate_upgrade_from_against_behavior(
21072            &[crate::UpgradeFromEntry {
21073                from: "0.2.0".into(),
21074                instructions: vec![
21075                    crate::UpgradeInstruction::LoadModule {
21076                        module: "demo".into(),
21077                    },
21078                    crate::UpgradeInstruction::StateChange {
21079                        script: std::path::PathBuf::from("lib/m.lisp"),
21080                    },
21081                ],
21082            }],
21083            None,
21084        )
21085        .unwrap_err();
21086        assert!(
21087            matches!(
21088                sanity,
21089                crate::UpgradeError::StateChangeWithoutOnStateChangeCallback { .. }
21090            ),
21091            "sanity: the missing-callback fixture alone must trip the \
21092             behavior arm — got {sanity:?}"
21093        );
21094    }
21095
21096    #[test]
21097    fn validate_upgrade_from_accepts_clean_fixture() {
21098        // Positive control: a well-formed `:upgrade-from` (single entry
21099        // with `:from` strictly less than `:versao`, no
21100        // `:state-change` instruction so the behavior arm is vacuous)
21101        // passes the compound gate cleanly. A future tightening of any
21102        // one arm's accepted set surfaces here as a test failure
21103        // first. Mirrors the peer `validate_versao_accepts_canonical_forms`
21104        // positive-control posture on the sibling per-Caixa gate.
21105        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21106        c.versao = "0.2.0".into();
21107        c.upgrade_from = vec![crate::UpgradeFromEntry {
21108            from: "0.1.0".into(),
21109            instructions: vec![crate::UpgradeInstruction::Restart],
21110        }];
21111        c.validate_upgrade_from()
21112            .expect("clean fixture must pass the compound `:upgrade-from` gate");
21113    }
21114
21115    #[test]
21116    fn validate_upgrade_from_accepts_empty_upgrade_from() {
21117        // Positive control on the empty-list arm: a caixa without any
21118        // `:upgrade-from` block (the default `Vec::new()`
21119        // `#[serde(default)]` folds an omitted slot onto) passes the
21120        // compound gate cleanly regardless of `:versao` or `:behavior`
21121        // — each of the three standalone validators is vacuous on the
21122        // empty entry list. Pins the identity element of the fold on
21123        // the empty-slot side.
21124        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21125        assert!(
21126            c.upgrade_from().is_empty(),
21127            "template caixa must carry an empty :upgrade-from — got {:?}",
21128            c.upgrade_from()
21129        );
21130        c.validate_upgrade_from()
21131            .expect("empty :upgrade-from must pass the compound gate cleanly");
21132    }
21133
21134    // ── Caixa::validate_limits — compound per-Caixa entry gate on   ──
21135    // ── the M2 `:limits` slot: folds the                            ──
21136    // ── [`crate::LimitsSpec::validate`] four-axis cascade on the    ──
21137    // ── present-slot arm and the `Option::None` identity element on ──
21138    // ── the absent-slot arm onto one substrate primitive.           ──
21139    // ── Byte-for-byte equivalent to the pre-fold                    ──
21140    // ── `if let Some(l) = caixa.limits() { l.validate() }`          ──
21141    // ── unwrap-and-dispatch pattern at                              ──
21142    // ── `crate::layout::StandardLayout::verify` (`layout.rs`).      ──
21143
21144    #[test]
21145    fn validate_limits_folds_arm_matches_gate() {
21146        // Fail-before-pass-after per-arm equivalence pin on the
21147        // present-slot arm: a fixture whose `:limits` carries a
21148        // zero-floor-violating `:fuel` (`Some(0)`, which
21149        // [`crate::LimitsSpec::validate`] rejects through
21150        // [`crate::LimitsError::FuelZero`]) surfaces the same
21151        // [`crate::LimitsError`] byte-equal through both the compound
21152        // gate [`Caixa::validate_limits`] and the standalone
21153        // [`crate::LimitsSpec::validate`] gate on the same `LimitsSpec`
21154        // value. Pins the fold — a silent regression that de-folded
21155        // the present-slot arm would surface here as a mismatch
21156        // between the two dispatches. Sibling in shape to the peer
21157        // per-arm equivalence pins the
21158        // [`crate::AplicacaoSpec::validate_contratos`] /
21159        // [`crate::MeshPolicy::validate`] /
21160        // [`crate::SupervisorSpec::validate_children`] /
21161        // [`Caixa::validate_upgrade_from`] compound gates each carry
21162        // on their axes.
21163        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21164        let l = crate::LimitsSpec {
21165            memory: None,
21166            fuel: Some(0),
21167            wall_clock: None,
21168            cpu: None,
21169        };
21170        c.limits = Some(l);
21171        let via_method = c.validate_limits().unwrap_err();
21172        let via_standalone = l.validate().unwrap_err();
21173        assert_eq!(
21174            via_method, via_standalone,
21175            "Caixa::validate_limits must surface the present-slot \
21176             arm's diagnostic byte-equal to the standalone \
21177             `LimitsSpec::validate` on the same `LimitsSpec` value"
21178        );
21179        assert!(
21180            matches!(via_method, crate::LimitsError::FuelZero),
21181            "expected FuelZero on the zero-floor-violating `:fuel`, \
21182             got {via_method:?}"
21183        );
21184    }
21185
21186    #[test]
21187    fn validate_limits_accepts_none() {
21188        // Positive control on the absent-slot arm (the fold's identity
21189        // element): a caixa without any `:limits` block (the
21190        // canonical "no bound declared — engine-default applies"
21191        // author shape [`crate::LimitsSpec::is_empty`]'s per-axis
21192        // `None` cascade reads, and the shape the [`Caixa::template`]
21193        // scaffold emits by construction) passes the compound gate
21194        // cleanly, regardless of any per-axis defect a subsequent
21195        // `Some(_)` binding would surface. Pins the identity element
21196        // of the fold on the absent-slot side, matching the peer
21197        // `validate_upgrade_from_accepts_empty_upgrade_from` positive-
21198        // control posture on the sibling M2 slot.
21199        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21200        assert!(
21201            c.limits().is_none(),
21202            "template caixa must carry an absent :limits — got {:?}",
21203            c.limits()
21204        );
21205        c.validate_limits()
21206            .expect("absent :limits must pass the compound gate cleanly");
21207    }
21208
21209    #[test]
21210    fn validate_limits_accepts_clean_fixture() {
21211        // Positive control on the present-slot arm: a caixa whose
21212        // `:limits` is `Some(LimitsSpec::default())` (all four axes
21213        // `None` — every axis absent under the outer `Some(_)`
21214        // binding, so every present-slot arm on
21215        // [`crate::LimitsSpec::validate`] is vacuous) passes the
21216        // compound gate cleanly. A future tightening of any one axis
21217        // that surfaces a diagnostic on the all-`None` `LimitsSpec`
21218        // would land here as a test failure first. Pins the
21219        // present-slot arm's accept-shape on the canonical
21220        // "declared-but-empty" author fixture the
21221        // `limits_round_trip_via_json` peer already round-trips
21222        // (`caixa-core/src/manifest.rs:6971`).
21223        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21224        c.limits = Some(crate::LimitsSpec::default());
21225        c.validate_limits()
21226            .expect("Some(LimitsSpec::default()) must pass the compound gate cleanly");
21227    }
21228
21229    // ── Caixa::validate_behavior — compound per-Caixa entry gate on ──
21230    // ── the M2 `:behavior` slot's pure value-shape surface: folds   ──
21231    // ── the [`crate::BehaviorSpec::validate`] six-slot cascade on   ──
21232    // ── the present-slot arm and the `Option::None` identity        ──
21233    // ── element on the absent-slot arm onto one substrate primitive.──
21234    // ── Byte-for-byte equivalent to the pre-fold                    ──
21235    // ── `if let Some(b) = caixa.behavior() { b.validate() }`        ──
21236    // ── unwrap-and-dispatch pattern at                              ──
21237    // ── `crate::layout::StandardLayout::verify` (`layout.rs`). The  ──
21238    // ── on-disk callback-path existence walk stays open-coded at    ──
21239    // ── the layout altitude because it needs the                    ──
21240    // ── [`crate::layout::LayoutInvariants::exists`] filesystem       ──
21241    // ── oracle the pure typed-shape surface has no reference to —   ──
21242    // ── mirror of the peer M2 `:upgrade-from` per-instruction       ──
21243    // ── script-path existence probe that stayed at the layout       ──
21244    // ── altitude after the [`Caixa::validate_upgrade_from`] lift    ──
21245    // ── (d6801df) for the same reason.                              ──
21246
21247    #[test]
21248    fn validate_behavior_folds_arm_matches_gate() {
21249        // Fail-before-pass-after per-arm equivalence pin on the
21250        // present-slot arm: a fixture whose `:behavior` carries an
21251        // absolute-path `:on-init` (`"/etc/passwd"`, which
21252        // [`crate::BehaviorSpec::validate`] rejects through
21253        // [`crate::BehaviorError::AbsolutePath`]) surfaces the same
21254        // [`crate::BehaviorError`] byte-equal through both the
21255        // compound gate [`Caixa::validate_behavior`] and the standalone
21256        // [`crate::BehaviorSpec::validate`] gate on the same
21257        // `BehaviorSpec` value. Pins the fold — a silent regression
21258        // that de-folded the present-slot arm would surface here as a
21259        // mismatch between the two dispatches. Sibling in shape to the
21260        // peer per-arm equivalence pins the
21261        // [`Caixa::validate_limits`] (baa4688),
21262        // [`Caixa::validate_upgrade_from`] (d6801df),
21263        // [`crate::MeshPolicy::validate`],
21264        // [`crate::AplicacaoSpec::validate_contratos`], and
21265        // [`crate::SupervisorSpec::validate_children`] compound gates
21266        // each carry on their axes.
21267        use crate::BehaviorSpec;
21268        use std::path::PathBuf;
21269        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21270        let b = BehaviorSpec {
21271            on_init: Some(PathBuf::from("/etc/passwd")),
21272            ..Default::default()
21273        };
21274        c.behavior = Some(b.clone());
21275        let via_method = c.validate_behavior().unwrap_err();
21276        let via_standalone = b.validate().unwrap_err();
21277        assert_eq!(
21278            via_method, via_standalone,
21279            "Caixa::validate_behavior must surface the present-slot \
21280             arm's diagnostic byte-equal to the standalone \
21281             `BehaviorSpec::validate` on the same `BehaviorSpec` value"
21282        );
21283        assert!(
21284            matches!(via_method, crate::BehaviorError::AbsolutePath { .. }),
21285            "expected AbsolutePath on the absolute `:on-init` path, \
21286             got {via_method:?}"
21287        );
21288    }
21289
21290    #[test]
21291    fn validate_behavior_accepts_none() {
21292        // Positive control on the absent-slot arm (the fold's identity
21293        // element): a caixa without any `:behavior` block (the
21294        // canonical "no callback declared — the runtime falls back to
21295        // the wasm-engine's default per arm" author shape
21296        // [`crate::BehaviorSpec::is_empty`]'s per-slot `None` cascade
21297        // reads, and the shape the [`Caixa::template`] scaffold emits
21298        // by construction) passes the compound gate cleanly,
21299        // regardless of any per-slot defect a subsequent `Some(_)`
21300        // binding would surface. Pins the identity element of the fold
21301        // on the absent-slot side, matching the peer
21302        // `validate_limits_accepts_none` (baa4688) and
21303        // `validate_upgrade_from_accepts_empty_upgrade_from` (d6801df)
21304        // positive-control postures on the sibling M2 slots.
21305        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21306        assert!(
21307            c.behavior().is_none(),
21308            "template caixa must carry an absent :behavior — got {:?}",
21309            c.behavior()
21310        );
21311        c.validate_behavior()
21312            .expect("absent :behavior must pass the compound gate cleanly");
21313    }
21314
21315    #[test]
21316    fn validate_behavior_accepts_clean_fixture() {
21317        // Positive control on the present-slot arm: a caixa whose
21318        // `:behavior` is `Some(BehaviorSpec::default())` (all six
21319        // slots `None` — every slot absent under the outer `Some(_)`
21320        // binding, so every present-slot arm on
21321        // [`crate::BehaviorSpec::validate`] is vacuous) passes the
21322        // compound gate cleanly. A future tightening of any one arm
21323        // that surfaces a diagnostic on the all-`None` `BehaviorSpec`
21324        // would land here as a test failure first. Pins the
21325        // present-slot arm's accept-shape on the canonical
21326        // "declared-but-empty" author fixture the sibling
21327        // `empty_behavior_round_trip` peer already round-trips
21328        // (`caixa-core/src/behavior.rs` tests). Mirror of the peer
21329        // `validate_limits_accepts_clean_fixture` (baa4688)
21330        // positive-control posture on the sibling M2 `:limits` slot.
21331        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21332        c.behavior = Some(crate::BehaviorSpec::default());
21333        c.validate_behavior()
21334            .expect("Some(BehaviorSpec::default()) must pass the compound gate cleanly");
21335    }
21336
21337    // ── Caixa::validate_deps — compound per-Caixa entry gate on the ──
21338    // ── dep-graph axis: folds the two standalone validators         ──
21339    // ── (per-entry + within-list duplicate walk that this method    ──
21340    // ── opened on, cross-slot self-edge via                         ──
21341    // ── `crate::dep::validate_no_self_dep`) onto one substrate      ──
21342    // ── primitive. Byte-for-byte equivalent to the pre-fold         ──
21343    // ── two-block cascade at                                        ──
21344    // ── `crate::layout::StandardLayout::verify` under the same      ──
21345    // ── canonical dispatch order (per-entry → self-edge).           ──
21346
21347    #[test]
21348    fn validate_deps_folds_per_entry_arm_matches_gate() {
21349        // Fail-before-pass-after per-arm equivalence pin on the
21350        // per-entry + within-list duplicate axis: a fixture whose
21351        // `:deps` carries a per-entry-invalid `:versao` (`"^bad"`,
21352        // which [`crate::parse_requirement`] rejects) surfaces the
21353        // same [`crate::DepError`] through the compound gate
21354        // [`Caixa::validate_deps`] and the standalone per-entry walk
21355        // ([`Dep::validate`]) on the offending entry. Pins the
21356        // fold — a silent regression that de-folded the per-entry arm
21357        // would surface here as a mismatch between the two
21358        // dispatches. Sibling in shape to the peer
21359        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
21360        // per-arm equivalence pin (d6801df) on the M2
21361        // `:upgrade-from` compound gate's per-entry arm, extended
21362        // here onto the universal-axis `:deps` compound gate's
21363        // per-entry arm.
21364        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21365        c.deps = vec![Dep::simple("d", "^bad")];
21366        let via_method = c.validate_deps().unwrap_err();
21367        let via_standalone = c.deps()[0].validate().unwrap_err();
21368        assert_eq!(
21369            via_method, via_standalone,
21370            "Caixa::validate_deps must surface the per-entry arm's \
21371             diagnostic byte-equal to the standalone \
21372             `Dep::validate` on the same offending entry",
21373        );
21374        assert!(
21375            matches!(
21376                via_method,
21377                DepError::VersaoInvalid { ref nome, .. } if nome == "d"
21378            ),
21379            "expected VersaoInvalid on the malformed :versao, got {via_method:?}",
21380        );
21381    }
21382
21383    #[test]
21384    fn validate_deps_folds_self_edge_arm_matches_gate() {
21385        // Per-arm equivalence pin on the cross-slot self-edge axis:
21386        // a fixture whose `:deps` lists the caixa's own `:nome`
21387        // (a self-dep, which
21388        // [`crate::dep::validate_no_self_dep`] rejects as a
21389        // structurally-invalid one-node cycle in the lacre closure's
21390        // dep-graph) surfaces the same [`crate::DepError::DepIsSelf`]
21391        // through both the compound gate and the standalone
21392        // [`crate::dep::validate_no_self_dep`] gate keyed off the
21393        // same `(deps, deps_dev, nome)` triple. Pins the fold's
21394        // second arm — reaching this arm through the compound gate
21395        // requires the per-entry + within-list duplicate walk to
21396        // pass first, which itself pins one cross-arm ordering step.
21397        // Sibling in shape to the peer
21398        // `validate_upgrade_from_folds_versao_arm_matches_gate` /
21399        // `_folds_behavior_arm_matches_gate` cross-slot equivalence
21400        // pins (d6801df) on the M2 `:upgrade-from` compound gate's
21401        // cross-slot arms.
21402        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21403        c.deps = vec![Dep::simple("demo", "^0.1")];
21404        let via_method = c.validate_deps().unwrap_err();
21405        let via_standalone =
21406            crate::dep::validate_no_self_dep(c.deps(), c.deps_dev(), c.nome()).unwrap_err();
21407        assert_eq!(
21408            via_method, via_standalone,
21409            "Caixa::validate_deps must surface the cross-slot \
21410             self-edge diagnostic byte-equal to the standalone \
21411             `crate::dep::validate_no_self_dep` on the same \
21412             (deps, deps_dev, nome) triple",
21413        );
21414        assert!(
21415            matches!(
21416                via_method,
21417                DepError::DepIsSelf { ref nome, list }
21418                    if nome == "demo" && list == crate::render::DEP_AUTHOR_KEY_DEPS
21419            ),
21420            "expected DepIsSelf carrying (nome=\"demo\", list=\":deps\"), got {via_method:?}",
21421        );
21422    }
21423
21424    #[test]
21425    fn validate_deps_per_entry_arm_fires_before_self_edge_arm() {
21426        // Cross-arm ordering pin between the two arms of the fold:
21427        // a fixture carrying BOTH a per-entry-invalid `:versao`
21428        // (`"^bad"` — [`crate::parse_requirement`] rejects the
21429        // requirement grammar) on a non-self-dep entry AND a
21430        // would-be self-edge violation on a second entry (the
21431        // caixa's own `:nome` "demo") surfaces the per-entry
21432        // diagnostic first through the compound gate. Sanity
21433        // assertion: the second entry alone under the same parent
21434        // `:nome` trips the self-edge arm on its own via the
21435        // standalone [`crate::dep::validate_no_self_dep`], so the
21436        // per-entry-first surfacing is a real ordering property,
21437        // not a case where the self-edge arm silently accepts the
21438        // fixture. Pins the pre-fold layout wire-up's canonical
21439        // dispatch order (per-entry + within-list duplicate →
21440        // self-edge) as a property of the substrate primitive
21441        // rather than a convention of the layout call site. Sibling
21442        // in shape to
21443        // `validate_upgrade_from_per_entry_arm_fires_before_versao_arm`
21444        // (d6801df) on the M2 `:upgrade-from` compound gate's
21445        // per-arm ordering property.
21446        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21447        c.deps = vec![
21448            Dep::simple("orquestra", "^bad"),
21449            Dep::simple("demo", "^0.1"),
21450        ];
21451        let err = c.validate_deps().unwrap_err();
21452        assert!(
21453            matches!(
21454                err,
21455                DepError::VersaoInvalid { ref nome, .. } if nome == "orquestra"
21456            ),
21457            "per-entry arm must fire before self-edge arm — expected \
21458             VersaoInvalid on \"orquestra\", got {err:?}",
21459        );
21460        // Sanity: the self-referential entry alone under the same
21461        // parent `:nome` trips the self-edge arm on its own — proves
21462        // the per-entry-first surfacing above is a real ordering
21463        // property, not a case where the self-edge arm silently
21464        // accepts the fixture.
21465        let sanity = crate::dep::validate_no_self_dep(&[Dep::simple("demo", "^0.1")], &[], "demo")
21466            .unwrap_err();
21467        assert!(
21468            matches!(sanity, DepError::DepIsSelf { ref nome, .. } if nome == "demo"),
21469            "sanity: the self-referential entry alone must trip the \
21470             self-edge arm — got {sanity:?}",
21471        );
21472    }
21473
21474    #[test]
21475    fn validate_deps_accepts_clean_fixture() {
21476        // Positive control: a well-formed dep-graph (one `:deps`
21477        // entry naming a non-self DNS-1123 nome + Cargo-shaped
21478        // requirement, one `:deps-dev` entry on a distinct non-self
21479        // nome) passes the compound gate cleanly. A future
21480        // tightening of either arm's accepted set surfaces here as
21481        // a test failure first. Mirrors the peer
21482        // `validate_upgrade_from_accepts_clean_fixture` positive-
21483        // control posture on the sibling per-Caixa compound gate.
21484        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21485        c.deps = vec![Dep::simple("caixa-teia", "^0.1")];
21486        c.deps_dev = vec![Dep::simple("caixa-lint", "^0.2")];
21487        c.validate_deps()
21488            .expect("clean fixture must pass the compound `:deps` gate");
21489    }
21490
21491    #[test]
21492    fn validate_deps_accepts_empty_deps_lists() {
21493        // Positive control on the empty-list arm: a caixa without
21494        // any `:deps` or `:deps-dev` entries (the default
21495        // `Vec::new()` `#[serde(default)]` folds an omitted slot
21496        // onto) passes the compound gate cleanly regardless of
21497        // `:nome` — both the per-entry walk and the self-edge walk
21498        // are vacuous on the empty entry list. Pins the identity
21499        // element of the fold on the empty-slot side, peer with the
21500        // `validate_upgrade_from_accepts_empty_upgrade_from` empty-
21501        // arm positive control (d6801df) on the sibling
21502        // `:upgrade-from` compound gate.
21503        let c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21504        assert!(
21505            c.deps().is_empty(),
21506            "template caixa must carry an empty :deps — got {:?}",
21507            c.deps(),
21508        );
21509        assert!(
21510            c.deps_dev().is_empty(),
21511            "template caixa must carry an empty :deps-dev — got {:?}",
21512            c.deps_dev(),
21513        );
21514        c.validate_deps()
21515            .expect("empty :deps / :deps-dev must pass the compound gate cleanly");
21516    }
21517
21518    // ── Caixa::validate_aplicacao_shape — compound per-Caixa gate ────────
21519
21520    /// Build a minimal well-formed Aplicacao fixture on top of the
21521    /// canonical template. Every arm of the compound gate then patches
21522    /// exactly one axis away from clean so its per-arm diagnostic
21523    /// surfaces without collateral noise from a peer slot.
21524    fn aplicacao_fixture(nome: &str) -> Caixa {
21525        use crate::aplicacao::{Membro, Placement, PlacementStrategy};
21526        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
21527        c.kind = CaixaKind::Aplicacao;
21528        c.bibliotecas = vec![];
21529        c.membros = vec![
21530            Membro {
21531                caixa: "checkout".into(),
21532                versao: "^0.1".into(),
21533            },
21534            Membro {
21535                caixa: "cart".into(),
21536                versao: "^0.1".into(),
21537            },
21538        ];
21539        // `:placement` defaults to `Replicated` with an empty
21540        // `:clusters` list which
21541        // [`crate::AplicacaoSpec::validate_placement`] refuses; every
21542        // per-strategy variant needs at least one named cluster (per
21543        // MESH-COMPOSITION §II.1). Pin a single-cluster `SingleNode`
21544        // placement so the typed-shape cascade passes cleanly and the
21545        // per-arm fixtures below can each patch exactly one axis.
21546        c.placement = Some(Placement {
21547            estrategia: PlacementStrategy::SingleNode,
21548            clusters: vec!["rio".into()],
21549            shard_key: None,
21550            affinity: None,
21551        });
21552        c
21553    }
21554
21555    #[test]
21556    fn validate_aplicacao_shape_folds_view_arm_matches_gate() {
21557        // Fail-before-pass-after per-arm equivalence pin on the
21558        // typed-shape cascade arm: a fixture whose typed
21559        // [`crate::AplicacaoSpec`] view fails
21560        // [`crate::AplicacaoSpec::validate`] (here — empty `:membros`,
21561        // which [`crate::AplicacaoSpec::validate_membros`] rejects as
21562        // [`crate::AplicacaoError::NoMembros`] at the first per-slot
21563        // gate) surfaces the same [`crate::AplicacaoError`] diagnostic
21564        // through both the compound gate
21565        // [`Caixa::validate_aplicacao_shape`] and the standalone
21566        // [`crate::AplicacaoSpec::validate`] on the same folded view.
21567        // Pins the fold — a silent regression that de-folded the
21568        // typed-shape arm would surface here as a mismatch between the
21569        // two dispatches. Sibling in shape to the peer
21570        // `validate_deps_folds_per_entry_arm_matches_gate` (b5dd55e) /
21571        // `validate_upgrade_from_folds_per_entry_arm_matches_gate`
21572        // (d6801df) per-arm equivalence pins on the sibling per-slot
21573        // compound gates.
21574        let mut c = aplicacao_fixture("demo");
21575        c.membros = vec![];
21576        let via_method = c.validate_aplicacao_shape().unwrap_err();
21577        let via_standalone = c.aplicacao_view().unwrap().validate().unwrap_err();
21578        assert_eq!(
21579            via_method, via_standalone,
21580            "Caixa::validate_aplicacao_shape must surface the typed-\
21581             shape arm's diagnostic byte-equal to the standalone \
21582             `AplicacaoSpec::validate` on the same folded view",
21583        );
21584        assert!(
21585            matches!(via_method, crate::AplicacaoError::NoMembros),
21586            "expected NoMembros on the empty :membros, got {via_method:?}",
21587        );
21588    }
21589
21590    #[test]
21591    fn validate_aplicacao_shape_folds_self_membership_arm_matches_gate() {
21592        // Per-arm equivalence pin on the cross-slot self-edge axis: a
21593        // fixture whose `:membros` names the Aplicacao's own `:nome`
21594        // (which [`crate::aplicacao::validate_no_self_membership`]
21595        // rejects as [`crate::AplicacaoError::MembroIsSelfAplicacao`],
21596        // a one-node lacre-closure recursion in the Aplicacao's
21597        // mesh-graph) surfaces the same
21598        // [`crate::AplicacaoError::MembroIsSelfAplicacao`] through both
21599        // the compound gate and the standalone
21600        // [`crate::aplicacao::validate_no_self_membership`] keyed off
21601        // the same `(membros, nome)` pair. Pins the fold's second arm
21602        // — reaching this arm through the compound gate requires the
21603        // typed-shape cascade to pass first, which itself pins one
21604        // cross-arm ordering step. Sibling in shape to the peer
21605        // `validate_deps_folds_self_edge_arm_matches_gate` (b5dd55e)
21606        // cross-slot equivalence pin on the sibling per-slot compound
21607        // gate.
21608        use crate::aplicacao::Membro;
21609        let mut c = aplicacao_fixture("demo");
21610        c.membros = vec![Membro {
21611            caixa: "demo".into(),
21612            versao: "^0.1".into(),
21613        }];
21614        let via_method = c.validate_aplicacao_shape().unwrap_err();
21615        let via_standalone =
21616            crate::aplicacao::validate_no_self_membership(c.membros(), c.nome()).unwrap_err();
21617        assert_eq!(
21618            via_method, via_standalone,
21619            "Caixa::validate_aplicacao_shape must surface the cross-\
21620             slot self-edge diagnostic byte-equal to the standalone \
21621             `aplicacao::validate_no_self_membership` on the same \
21622             (membros, nome) pair",
21623        );
21624        assert!(
21625            matches!(
21626                via_method,
21627                crate::AplicacaoError::MembroIsSelfAplicacao { ref caixa } if caixa == "demo"
21628            ),
21629            "expected MembroIsSelfAplicacao carrying (caixa=\"demo\"), \
21630             got {via_method:?}",
21631        );
21632    }
21633
21634    #[test]
21635    fn validate_aplicacao_shape_view_arm_fires_before_self_membership_arm() {
21636        // Cross-arm ordering pin between the two arms of the fold: a
21637        // fixture carrying BOTH a typed-shape violation (a `:contratos`
21638        // edge whose `:para` is not a declared member — rejected by
21639        // [`crate::AplicacaoSpec::validate_contratos`] as
21640        // [`crate::AplicacaoError::ContratoMemberMissing`]) AND a
21641        // would-be self-edge violation (a `:membros` entry naming the
21642        // caixa's own `:nome`) surfaces the typed-shape diagnostic
21643        // first through the compound gate. Sanity assertion: the
21644        // self-referential `:membros` entry alone under the same
21645        // parent `:nome` trips the self-edge arm on its own via the
21646        // standalone [`crate::aplicacao::validate_no_self_membership`],
21647        // so the typed-shape-first surfacing is a real ordering
21648        // property, not a case where the self-edge arm silently
21649        // accepts the fixture. Pins the pre-fold layout wire-up's
21650        // canonical dispatch order (typed-shape cascade → cross-slot
21651        // self-edge) as a property of the substrate primitive rather
21652        // than a convention of the layout call site. Sibling in shape
21653        // to `validate_deps_per_entry_arm_fires_before_self_edge_arm`
21654        // (b5dd55e) on the sibling per-slot compound gate's per-arm
21655        // ordering property.
21656        use crate::aplicacao::{Membro, WitContract};
21657        let mut c = aplicacao_fixture("demo");
21658        c.membros = vec![Membro {
21659            caixa: "demo".into(),
21660            versao: "^0.1".into(),
21661        }];
21662        c.contratos = vec![WitContract {
21663            de: "demo".into(),
21664            para: "orphan".into(),
21665            wit: "wasi:http/proxy".into(),
21666            endpoint: Some("/x".into()),
21667            subject: None,
21668            slot: None,
21669        }];
21670        let err = c.validate_aplicacao_shape().unwrap_err();
21671        assert!(
21672            matches!(
21673                err,
21674                crate::AplicacaoError::ContratoMemberMissing { ref caixa }
21675                    if caixa == "orphan"
21676            ),
21677            "typed-shape arm must fire before self-edge arm — expected \
21678             ContratoMemberMissing on \"orphan\", got {err:?}",
21679        );
21680        // Sanity: the self-referential `:membros` entry alone under
21681        // the same parent `:nome` trips the self-edge arm on its own
21682        // — proves the typed-shape-first surfacing above is a real
21683        // ordering property, not a case where the self-edge arm
21684        // silently accepts the fixture.
21685        let sanity = crate::aplicacao::validate_no_self_membership(
21686            &[Membro {
21687                caixa: "demo".into(),
21688                versao: "^0.1".into(),
21689            }],
21690            "demo",
21691        )
21692        .unwrap_err();
21693        assert!(
21694            matches!(
21695                sanity,
21696                crate::AplicacaoError::MembroIsSelfAplicacao { ref caixa }
21697                    if caixa == "demo"
21698            ),
21699            "sanity: the self-referential :membros entry alone must \
21700             trip the self-edge arm — got {sanity:?}",
21701        );
21702    }
21703
21704    #[test]
21705    fn validate_aplicacao_shape_accepts_non_aplicacao_kind() {
21706        // Positive control on the identity-element arm: every non-
21707        // Aplicacao kind passes the compound gate trivially — the
21708        // paired [`Caixa::aplicacao_view`] accessor returns `None`
21709        // off the Aplicacao arm (by construction, keyed on
21710        // `caixa.kind().is_aplicacao()`), so the fold short-circuits
21711        // to `Ok(())` without touching the mesh slots. Pins the
21712        // identity element on every non-Aplicacao kind — a future
21713        // refactor that made the mesh-slot cascade fire on the wrong
21714        // kind (say, on a `Servico` whose mesh slots happen to be
21715        // populated in a mis-authored manifest, which the peer
21716        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] kind-
21717        // coherence gate would refuse upstream anyway) surfaces here
21718        // as a test failure first. Peer with the
21719        // `validate_limits_accepts_none` / `validate_behavior_accepts_none`
21720        // identity-element pins on the sibling M2 `Option`-shaped
21721        // per-Caixa compound gates.
21722        for kind in [
21723            CaixaKind::Biblioteca,
21724            CaixaKind::Binario,
21725            CaixaKind::Servico,
21726            CaixaKind::Supervisor,
21727            CaixaKind::Acao,
21728        ] {
21729            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21730            c.kind = kind;
21731            assert!(
21732                c.aplicacao_view().is_none(),
21733                "aplicacao_view must return None off the Aplicacao arm \
21734                 for kind {kind:?}",
21735            );
21736            c.validate_aplicacao_shape().expect(
21737                "non-Aplicacao kinds must pass the compound gate as the fold's identity element",
21738            );
21739        }
21740    }
21741
21742    #[test]
21743    fn validate_aplicacao_shape_accepts_clean_fixture() {
21744        // Positive control: a well-formed Aplicacao (two DNS-1123
21745        // members with valid semver constraints, no `:contratos` /
21746        // `:entrada` / `:placement` / `:politicas` set — every
21747        // per-slot gate accepts the vacuous / omitted arm) passes the
21748        // compound gate cleanly. A future tightening of either arm's
21749        // accepted set surfaces here as a test failure first. Mirrors
21750        // the peer `validate_deps_accepts_clean_fixture` (b5dd55e) /
21751        // `validate_upgrade_from_accepts_clean_fixture` (d6801df)
21752        // positive-control postures on the sibling per-Caixa
21753        // compound gates.
21754        let c = aplicacao_fixture("demo");
21755        c.validate_aplicacao_shape()
21756            .expect("clean Aplicacao fixture must pass the compound gate");
21757    }
21758
21759    // ── Caixa::validate_supervisor_shape — compound per-Caixa gate ───────
21760
21761    /// Build a minimal well-formed Supervisor fixture on top of the
21762    /// canonical template. Every arm of the compound gate then patches
21763    /// exactly one axis away from clean so its per-arm diagnostic
21764    /// surfaces without collateral noise from a peer slot. Peer of
21765    /// [`aplicacao_fixture`] on the sibling per-Aplicacao compound
21766    /// gate's pin family.
21767    fn supervisor_fixture(nome: &str) -> Caixa {
21768        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
21769        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
21770        c.kind = CaixaKind::Supervisor;
21771        // Supervisors don't run code — clear the biblioteca slot the
21772        // template seeds so the fold's per-arm diagnostics surface
21773        // without the peer `SupervisorOwnsCode` kind-coherence gate
21774        // firing upstream at the layout altitude.
21775        c.bibliotecas = vec![];
21776        // `:estrategia` defaults to `OneForOne` at the typed view level,
21777        // and `OneForOne` requires at least one `:children` entry — pin
21778        // a single-child `Permanent` worker so the typed-shape cascade
21779        // passes cleanly and the per-arm fixtures below can each patch
21780        // exactly one axis.
21781        c.estrategia = Some(RestartStrategy::OneForOne);
21782        c.children = vec![ChildSpec {
21783            caixa: "worker".into(),
21784            versao: "^0.1".into(),
21785            restart: RestartPolicy::Permanent,
21786        }];
21787        c
21788    }
21789
21790    #[test]
21791    fn validate_supervisor_shape_folds_view_arm_matches_gate() {
21792        // Fail-before-pass-after per-arm equivalence pin on the
21793        // typed-shape cascade arm: a fixture whose typed
21794        // [`crate::SupervisorSpec`] view fails
21795        // [`crate::SupervisorSpec::validate`] (here — a duplicate
21796        // `:children` `:caixa` entry, which
21797        // [`crate::SupervisorSpec::validate`]'s set-not-multiset gate
21798        // rejects as [`crate::SupervisorError::DuplicateChildCaixa`])
21799        // surfaces the same [`crate::SupervisorError`] diagnostic
21800        // through both the compound gate
21801        // [`Caixa::validate_supervisor_shape`] and the standalone
21802        // [`crate::SupervisorSpec::validate`] on the same folded view.
21803        // Pins the fold — a silent regression that de-folded the
21804        // typed-shape arm would surface here as a mismatch between the
21805        // two dispatches. Sibling in shape to the peer
21806        // `validate_aplicacao_shape_folds_view_arm_matches_gate`
21807        // (949a7a0) on the sibling per-Aplicacao compound gate.
21808        use crate::supervisor::{ChildSpec, RestartPolicy};
21809        let mut c = supervisor_fixture("demo");
21810        c.children = vec![
21811            ChildSpec {
21812                caixa: "worker".into(),
21813                versao: "^0.1".into(),
21814                restart: RestartPolicy::Permanent,
21815            },
21816            ChildSpec {
21817                caixa: "worker".into(),
21818                versao: "^0.1".into(),
21819                restart: RestartPolicy::Permanent,
21820            },
21821        ];
21822        let via_method = c.validate_supervisor_shape().unwrap_err();
21823        let via_standalone = c.supervisor_view().unwrap().validate().unwrap_err();
21824        assert_eq!(
21825            via_method, via_standalone,
21826            "Caixa::validate_supervisor_shape must surface the typed-\
21827             shape arm's diagnostic byte-equal to the standalone \
21828             `SupervisorSpec::validate` on the same folded view",
21829        );
21830        assert!(
21831            matches!(
21832                via_method,
21833                crate::SupervisorError::DuplicateChildCaixa { ref caixa }
21834                    if caixa == "worker"
21835            ),
21836            "expected DuplicateChildCaixa on the duplicate 'worker' \
21837             child, got {via_method:?}",
21838        );
21839    }
21840
21841    #[test]
21842    fn validate_supervisor_shape_folds_self_supervision_arm_matches_gate() {
21843        // Per-arm equivalence pin on the cross-slot self-edge axis: a
21844        // fixture whose `:children :caixa` names the Supervisor's own
21845        // `:nome` (which
21846        // [`crate::supervisor::validate_no_self_supervision`] rejects
21847        // as [`crate::SupervisorError::ChildSupervisesSelf`], a
21848        // one-node reconciliation cycle in the supervisor's
21849        // supervision-tree) surfaces the same
21850        // [`crate::SupervisorError::ChildSupervisesSelf`] through both
21851        // the compound gate and the standalone
21852        // [`crate::supervisor::validate_no_self_supervision`] keyed
21853        // off the same `(children, nome)` pair. Pins the fold's
21854        // second arm — reaching this arm through the compound gate
21855        // requires the typed-shape cascade to pass first, which itself
21856        // pins one cross-arm ordering step. Sibling in shape to the
21857        // peer
21858        // `validate_aplicacao_shape_folds_self_membership_arm_matches_gate`
21859        // (949a7a0) cross-slot equivalence pin on the sibling
21860        // per-Aplicacao compound gate.
21861        use crate::supervisor::{ChildSpec, RestartPolicy};
21862        let mut c = supervisor_fixture("demo");
21863        c.children = vec![ChildSpec {
21864            caixa: "demo".into(),
21865            versao: "^0.1".into(),
21866            restart: RestartPolicy::Permanent,
21867        }];
21868        let via_method = c.validate_supervisor_shape().unwrap_err();
21869        let via_standalone =
21870            crate::supervisor::validate_no_self_supervision(c.children(), c.nome()).unwrap_err();
21871        assert_eq!(
21872            via_method, via_standalone,
21873            "Caixa::validate_supervisor_shape must surface the cross-\
21874             slot self-edge diagnostic byte-equal to the standalone \
21875             `supervisor::validate_no_self_supervision` on the same \
21876             (children, nome) pair",
21877        );
21878        assert!(
21879            matches!(
21880                via_method,
21881                crate::SupervisorError::ChildSupervisesSelf { ref caixa } if caixa == "demo"
21882            ),
21883            "expected ChildSupervisesSelf carrying (caixa=\"demo\"), \
21884             got {via_method:?}",
21885        );
21886    }
21887
21888    #[test]
21889    fn validate_supervisor_shape_view_arm_fires_before_self_supervision_arm() {
21890        // Cross-arm ordering pin between the two arms of the fold: a
21891        // fixture carrying BOTH a typed-shape violation (a per-child
21892        // empty `:caixa` name — rejected by
21893        // [`crate::SupervisorSpec::validate`] as
21894        // [`crate::SupervisorError::EmptyChildName`]) AND a would-be
21895        // self-edge violation (a `:children` entry naming the
21896        // supervisor's own `:nome`) surfaces the typed-shape
21897        // diagnostic first through the compound gate. Sanity
21898        // assertion: the self-referential `:children` entry alone
21899        // under the same parent `:nome` trips the self-edge arm on
21900        // its own via the standalone
21901        // [`crate::supervisor::validate_no_self_supervision`], so the
21902        // typed-shape-first surfacing is a real ordering property, not
21903        // a case where the self-edge arm silently accepts the fixture.
21904        // Pins the pre-fold layout wire-up's canonical dispatch order
21905        // (typed-shape cascade → cross-slot self-edge) as a property
21906        // of the substrate primitive rather than a convention of the
21907        // layout call site. Sibling in shape to
21908        // `validate_aplicacao_shape_view_arm_fires_before_self_membership_arm`
21909        // (949a7a0) on the sibling per-Aplicacao compound gate.
21910        use crate::supervisor::{ChildSpec, RestartPolicy};
21911        let mut c = supervisor_fixture("demo");
21912        c.children = vec![
21913            ChildSpec {
21914                caixa: String::new(),
21915                versao: "^0.1".into(),
21916                restart: RestartPolicy::Permanent,
21917            },
21918            ChildSpec {
21919                caixa: "demo".into(),
21920                versao: "^0.1".into(),
21921                restart: RestartPolicy::Permanent,
21922            },
21923        ];
21924        let err = c.validate_supervisor_shape().unwrap_err();
21925        assert!(
21926            matches!(err, crate::SupervisorError::EmptyChildName),
21927            "typed-shape arm must fire before self-edge arm — expected \
21928             EmptyChildName on the empty :caixa child, got {err:?}",
21929        );
21930        // Sanity: the self-referential `:children` entry alone under
21931        // the same parent `:nome` trips the self-edge arm on its own
21932        // — proves the typed-shape-first surfacing above is a real
21933        // ordering property, not a case where the self-edge arm
21934        // silently accepts the fixture.
21935        let sanity = crate::supervisor::validate_no_self_supervision(
21936            &[ChildSpec {
21937                caixa: "demo".into(),
21938                versao: "^0.1".into(),
21939                restart: RestartPolicy::Permanent,
21940            }],
21941            "demo",
21942        )
21943        .unwrap_err();
21944        assert!(
21945            matches!(
21946                sanity,
21947                crate::SupervisorError::ChildSupervisesSelf { ref caixa } if caixa == "demo"
21948            ),
21949            "sanity: the self-referential :children entry alone must \
21950             trip the self-edge arm — got {sanity:?}",
21951        );
21952    }
21953
21954    #[test]
21955    fn validate_supervisor_shape_accepts_non_supervisor_kind() {
21956        // Positive control on the identity-element arm: every non-
21957        // Supervisor kind passes the compound gate trivially — the
21958        // paired [`Caixa::supervisor_view`] accessor returns `None`
21959        // off the Supervisor arm (by construction, keyed on
21960        // `caixa.kind().is_supervisor()`), so the fold short-circuits
21961        // to `Ok(())` without touching the supervision-tree slots.
21962        // Pins the identity element on every non-Supervisor kind — a
21963        // future refactor that made the supervision-tree cascade fire
21964        // on the wrong kind (say, on a `Servico` whose supervision
21965        // slots happen to be populated in a mis-authored manifest,
21966        // which the peer
21967        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
21968        // kind-coherence gate would refuse upstream anyway) surfaces
21969        // here as a test failure first. Peer with the
21970        // `validate_aplicacao_shape_accepts_non_aplicacao_kind`
21971        // (949a7a0) / `validate_limits_accepts_none` /
21972        // `validate_behavior_accepts_none` identity-element pins on
21973        // the sibling per-Caixa compound gates.
21974        for kind in [
21975            CaixaKind::Biblioteca,
21976            CaixaKind::Binario,
21977            CaixaKind::Servico,
21978            CaixaKind::Aplicacao,
21979            CaixaKind::Acao,
21980        ] {
21981            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
21982            c.kind = kind;
21983            assert!(
21984                c.supervisor_view().is_none(),
21985                "supervisor_view must return None off the Supervisor \
21986                 arm for kind {kind:?}",
21987            );
21988            c.validate_supervisor_shape().expect(
21989                "non-Supervisor kinds must pass the compound gate as the fold's identity element",
21990            );
21991        }
21992    }
21993
21994    #[test]
21995    fn validate_supervisor_shape_accepts_clean_fixture() {
21996        // Positive control: a well-formed Supervisor (single
21997        // DNS-1123-valid `Permanent` worker child under the
21998        // `OneForOne` strategy — the OTP MaxIntensity/Period defaults
21999        // accept the vacuous `:max-restarts` / `:restart-window`
22000        // arms) passes the compound gate cleanly. A future tightening
22001        // of either arm's accepted set surfaces here as a test
22002        // failure first. Mirrors the peer
22003        // `validate_aplicacao_shape_accepts_clean_fixture` (949a7a0)
22004        // positive-control posture on the sibling per-Caixa compound
22005        // gate.
22006        let c = supervisor_fixture("demo");
22007        c.validate_supervisor_shape()
22008            .expect("clean Supervisor fixture must pass the compound gate");
22009    }
22010
22011    // ── Caixa::validate_acao_shape — compound per-Caixa gate ─────────────
22012
22013    /// Build a minimal well-formed `:kind Acao` fixture with a valid
22014    /// two-node acyclic `:ci` slot. Every arm of the compound gate
22015    /// then patches exactly one axis away from clean so its per-arm
22016    /// diagnostic surfaces without collateral noise from a peer slot.
22017    /// Peer of [`supervisor_fixture`] / [`aplicacao_fixture`] on the
22018    /// sibling per-kind compound gates' pin families.
22019    fn acao_fixture(nome: &str) -> Caixa {
22020        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
22021        c.kind = CaixaKind::Acao;
22022        // Acaos don't run code — clear the biblioteca slot the template
22023        // seeds so the compound gate's per-arm diagnostics surface
22024        // without the peer `AcaoOwnsCode` kind-coherence gate firing
22025        // upstream at the layout altitude.
22026        c.bibliotecas = vec![];
22027        c.ci = Some(canteiro_types::CiRun {
22028            workspace: "pleme-io".into(),
22029            repo: "caixa".into(),
22030            nodes: vec![
22031                canteiro_types::CiNode::new(
22032                    "build",
22033                    canteiro_types::EnvClass::None,
22034                    canteiro_types::ActionRef {
22035                        name: "build".into(),
22036                        command: "true".into(),
22037                        args: vec![],
22038                    },
22039                    vec![],
22040                ),
22041                canteiro_types::CiNode::new(
22042                    "test",
22043                    canteiro_types::EnvClass::None,
22044                    canteiro_types::ActionRef {
22045                        name: "test".into(),
22046                        command: "true".into(),
22047                        args: vec![],
22048                    },
22049                    vec!["build".into()],
22050                ),
22051            ],
22052        });
22053        c
22054    }
22055
22056    #[test]
22057    fn validate_acao_shape_folds_decompose_arm_matches_gate() {
22058        // Fail-before-pass-after per-arm equivalence pin on the
22059        // decompose axis: a fixture whose `:ci` slot fails
22060        // [`canteiro_types::decompose`] (here — a minimal two-node
22061        // cycle `a → b → a`, which the sibling
22062        // [`crate::render::decompose_ci`] wraps as
22063        // [`crate::CiDecomposeFailure`] carrying
22064        // [`canteiro_types::DecomposeError::Cycle`]) surfaces the same
22065        // [`crate::CiDecomposeFailure`] diagnostic through both the
22066        // compound gate [`Caixa::validate_acao_shape`] and the
22067        // standalone [`crate::render::decompose_ci`] on the same
22068        // `(caixa, ci)` fixture. Pins the fold — a silent regression
22069        // that de-folded the decompose arm would surface here as a
22070        // mismatch between the two dispatches. Sibling in shape to the
22071        // peer `validate_supervisor_shape_folds_view_arm_matches_gate`
22072        // / `validate_aplicacao_shape_folds_view_arm_matches_gate` on
22073        // the sibling per-kind compound gates.
22074        //
22075        // [`crate::CiDecomposeFailure`] does not derive `PartialEq`
22076        // (its `#[source]` carrier [`canteiro_types::DecomposeError`]
22077        // does, but the wrapper deliberately does not), so the two
22078        // dispatches are compared through their field pair
22079        // (`nome` + `source`) rather than through `assert_eq!` on the
22080        // wrapper itself — every field on the wrapper is thereby
22081        // pinned byte-equal without depending on an implementation
22082        // detail of `CiDecomposeFailure`'s derive set.
22083        let mut c = acao_fixture("demo");
22084        c.ci = Some(canteiro_types::CiRun {
22085            workspace: "pleme-io".into(),
22086            repo: "caixa".into(),
22087            nodes: vec![
22088                canteiro_types::CiNode::new(
22089                    "a",
22090                    canteiro_types::EnvClass::None,
22091                    canteiro_types::ActionRef {
22092                        name: "a".into(),
22093                        command: "true".into(),
22094                        args: vec![],
22095                    },
22096                    vec!["b".into()],
22097                ),
22098                canteiro_types::CiNode::new(
22099                    "b",
22100                    canteiro_types::EnvClass::None,
22101                    canteiro_types::ActionRef {
22102                        name: "b".into(),
22103                        command: "true".into(),
22104                        args: vec![],
22105                    },
22106                    vec!["a".into()],
22107                ),
22108            ],
22109        });
22110        let via_method = c.validate_acao_shape().unwrap_err();
22111        let via_standalone =
22112            crate::render::decompose_ci(&c, c.ci().expect("fixture has a :ci")).unwrap_err();
22113        assert_eq!(
22114            via_method.nome, via_standalone.nome,
22115            "Caixa::validate_acao_shape must surface the decompose \
22116             failure's `nome` byte-equal to the standalone \
22117             `decompose_ci` on the same (caixa, ci) fixture",
22118        );
22119        assert_eq!(
22120            via_method.source, via_standalone.source,
22121            "Caixa::validate_acao_shape must surface the decompose \
22122             failure's `source` byte-equal to the standalone \
22123             `decompose_ci` on the same (caixa, ci) fixture",
22124        );
22125        assert_eq!(
22126            via_method.source,
22127            canteiro_types::DecomposeError::Cycle,
22128            "expected the two-node cycle `a → b → a` to surface as \
22129             DecomposeError::Cycle, got {source:?}",
22130            source = via_method.source,
22131        );
22132    }
22133
22134    #[test]
22135    fn validate_acao_shape_folds_duplicate_node_arm_matches_gate() {
22136        // Per-arm equivalence pin on the `DuplicateNode` decompose
22137        // arm — the sibling of `Cycle` on the substrate's
22138        // `canteiro_types::DecomposeError` enumeration. A fixture
22139        // whose `:ci` slot carries two nodes sharing one name
22140        // surfaces the same [`crate::CiDecomposeFailure`] through
22141        // both dispatches, pinned by field pair. The three
22142        // decompose arms (`DuplicateNode` / `UnknownDep` / `Cycle`)
22143        // together enumerate every failure mode
22144        // [`canteiro_types::decompose`] refuses, so the per-arm
22145        // pins collectively cover the whole decompose axis.
22146        let mut c = acao_fixture("demo");
22147        c.ci = Some(canteiro_types::CiRun {
22148            workspace: "pleme-io".into(),
22149            repo: "caixa".into(),
22150            nodes: vec![
22151                canteiro_types::CiNode::new(
22152                    "twin",
22153                    canteiro_types::EnvClass::None,
22154                    canteiro_types::ActionRef {
22155                        name: "twin".into(),
22156                        command: "true".into(),
22157                        args: vec![],
22158                    },
22159                    vec![],
22160                ),
22161                canteiro_types::CiNode::new(
22162                    "twin",
22163                    canteiro_types::EnvClass::None,
22164                    canteiro_types::ActionRef {
22165                        name: "twin".into(),
22166                        command: "true".into(),
22167                        args: vec![],
22168                    },
22169                    vec![],
22170                ),
22171            ],
22172        });
22173        let via_method = c.validate_acao_shape().unwrap_err();
22174        assert_eq!(
22175            via_method.source,
22176            canteiro_types::DecomposeError::DuplicateNode("twin".into()),
22177            "expected DuplicateNode on the two-\"twin\"-name fixture, \
22178             got {source:?}",
22179            source = via_method.source,
22180        );
22181    }
22182
22183    #[test]
22184    fn validate_acao_shape_folds_unknown_dep_arm_matches_gate() {
22185        // Per-arm equivalence pin on the `UnknownDep` decompose arm —
22186        // the third and last arm on `canteiro_types::DecomposeError`
22187        // after `Cycle` and `DuplicateNode`. A fixture whose `:ci`
22188        // slot names a `deps` entry no declared node satisfies
22189        // surfaces the same [`crate::CiDecomposeFailure`] through
22190        // both dispatches. Pins the third decompose arm at the
22191        // compound gate.
22192        let mut c = acao_fixture("demo");
22193        c.ci = Some(canteiro_types::CiRun {
22194            workspace: "pleme-io".into(),
22195            repo: "caixa".into(),
22196            nodes: vec![canteiro_types::CiNode::new(
22197                "orphan",
22198                canteiro_types::EnvClass::None,
22199                canteiro_types::ActionRef {
22200                    name: "orphan".into(),
22201                    command: "true".into(),
22202                    args: vec![],
22203                },
22204                vec!["ghost".into()],
22205            )],
22206        });
22207        let via_method = c.validate_acao_shape().unwrap_err();
22208        assert_eq!(
22209            via_method.source,
22210            canteiro_types::DecomposeError::UnknownDep {
22211                node: "orphan".into(),
22212                dep: "ghost".into(),
22213            },
22214            "expected UnknownDep on the orphan-node-depends-on-ghost \
22215             fixture, got {source:?}",
22216            source = via_method.source,
22217        );
22218    }
22219
22220    #[test]
22221    fn validate_acao_shape_accepts_non_acao_kind() {
22222        // Positive control on the identity-element arm: every non-
22223        // Acao kind passes the compound gate trivially — the paired
22224        // `caixa.kind().is_acao()` guard short-circuits before the
22225        // decompose gate ever fires, so the fold returns `Ok(())`
22226        // without touching the `:ci` slot even when a non-Acao
22227        // fixture happens to declare one (the sibling
22228        // [`crate::LayoutError::CiOnNonAcao`] kind-coherence gate
22229        // catches that at the layout altitude anyway). Pins the
22230        // identity element on every non-Acao kind. Peer with the
22231        // `validate_supervisor_shape_accepts_non_supervisor_kind` /
22232        // `validate_aplicacao_shape_accepts_non_aplicacao_kind`
22233        // identity-element pins on the sibling per-Caixa compound
22234        // gates.
22235        for kind in [
22236            CaixaKind::Biblioteca,
22237            CaixaKind::Binario,
22238            CaixaKind::Servico,
22239            CaixaKind::Supervisor,
22240            CaixaKind::Aplicacao,
22241        ] {
22242            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22243            c.kind = kind;
22244            c.validate_acao_shape().expect(
22245                "non-Acao kinds must pass the compound gate as the fold's identity element",
22246            );
22247        }
22248    }
22249
22250    #[test]
22251    fn validate_acao_shape_accepts_absent_ci_slot() {
22252        // Positive control on the second identity-element arm: a
22253        // `:kind Acao` caixa with `ci = None` passes the compound
22254        // gate trivially — the presence gate is the sibling axis
22255        // owned by [`crate::LayoutError::MissingCi`] /
22256        // [`crate::require_ci`] / [`crate::MissingCiSlot`], not by
22257        // the decompose gate. A caixa that carries no `:ci` slot
22258        // has no run to decompose, so the fold's `let Some(ci) = …
22259        // else { return Ok(()) }` arm short-circuits before the
22260        // decompose gate fires. Pins that the two axes stay
22261        // separately diagnosable at the layout altitude — a future
22262        // regression that collapsed the presence gate onto the
22263        // shape gate here would land a
22264        // [`crate::CiDecomposeFailure`] on the wrong axis and
22265        // surface an off-target diagnostic at `feira build` time.
22266        let mut c = acao_fixture("demo");
22267        c.ci = None;
22268        c.validate_acao_shape().expect(
22269            "an :kind Acao caixa with absent :ci must pass the compound gate — \
22270             the presence gate is layout's MissingCi axis, not the decompose gate",
22271        );
22272    }
22273
22274    #[test]
22275    fn validate_acao_shape_accepts_clean_fixture() {
22276        // Positive control: a well-formed Acao (a two-node acyclic
22277        // `:ci` run with `test` depending on `build`) passes the
22278        // compound gate cleanly. A future tightening of the
22279        // decompose gate's accepted set surfaces here as a test
22280        // failure first. Mirrors the peer
22281        // `validate_supervisor_shape_accepts_clean_fixture` /
22282        // `validate_aplicacao_shape_accepts_clean_fixture`
22283        // positive-control posture on the sibling per-Caixa
22284        // compound gates.
22285        let c = acao_fixture("demo");
22286        c.validate_acao_shape()
22287            .expect("clean Acao fixture must pass the compound gate");
22288    }
22289
22290    fn bare_servico_fixture(nome: &str) -> Caixa {
22291        // A minimal Servico caixa with no code and no typed slots —
22292        // the cross-family fold's identity element on every arm.
22293        // Clears the biblioteca slot the template seeds so the
22294        // per-arm patches below can each add exactly one typed slot
22295        // without a peer `ServicoOwnsCode` / layout-side kind-gate
22296        // firing upstream.
22297        let mut c = Caixa::from_lisp(&Caixa::template(nome)).unwrap();
22298        c.kind = CaixaKind::Servico;
22299        c.bibliotecas = vec![];
22300        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
22301        c
22302    }
22303
22304    #[test]
22305    fn validate_kind_slot_coherence_folds_mesh_arm_matches_gate() {
22306        // Fail-before-pass-after per-arm equivalence pin on the M3
22307        // mesh-slot arm of the cross-family kind-coherence fold: a
22308        // non-Aplicacao caixa carrying a declared M3 mesh slot (here
22309        // a `:kind Servico` fixture with a single `:membros` entry —
22310        // the smallest possible M3 slot declaration on a foreign
22311        // kind) surfaces the same
22312        // [`crate::LayoutError::MeshSlotsOnNonAplicacao`] variant
22313        // through both the compound gate
22314        // [`Caixa::validate_kind_slot_coherence`] and the standalone
22315        // constructor [`crate::LayoutError::mesh_slots_on_non_aplicacao`]
22316        // dispatched on the same `declared_mesh_slots` list. Pins
22317        // the fold — a silent regression that de-folded the mesh
22318        // arm would surface here as a mismatch between the two
22319        // dispatches. Sibling in shape to the peer
22320        // `validate_aplicacao_shape_folds_view_arm_matches_gate` /
22321        // `validate_supervisor_shape_folds_view_arm_matches_gate` /
22322        // `validate_acao_shape_folds_decompose_arm_matches_gate`
22323        // per-arm equivalence pins on the sibling per-kind compound
22324        // gates.
22325        use crate::aplicacao::Membro;
22326        let mut c = bare_servico_fixture("demo");
22327        c.membros = vec![Membro {
22328            caixa: "cart".into(),
22329            versao: "^0.1".into(),
22330        }];
22331        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22332        let via_standalone =
22333            crate::LayoutError::mesh_slots_on_non_aplicacao(&c, c.declared_mesh_slots());
22334        assert_eq!(
22335            via_method, via_standalone,
22336            "Caixa::validate_kind_slot_coherence must surface the M3 \
22337             mesh-slot arm's diagnostic byte-equal to the standalone \
22338             LayoutError::mesh_slots_on_non_aplicacao ctor on the same \
22339             declared_mesh_slots list",
22340        );
22341    }
22342
22343    #[test]
22344    fn validate_kind_slot_coherence_folds_supervisor_arm_matches_gate() {
22345        // Per-arm equivalence pin on the supervisor-tree arm — the
22346        // sibling of the mesh arm on the cross-family fold. A
22347        // non-Supervisor caixa carrying a declared supervisor slot
22348        // (a `:kind Servico` fixture with `:estrategia` set — the
22349        // smallest possible supervisor slot declaration on a
22350        // foreign kind) surfaces the same
22351        // [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
22352        // variant through both dispatches, pinned by field pair
22353        // through `PartialEq`.
22354        use crate::supervisor::RestartStrategy;
22355        let mut c = bare_servico_fixture("demo");
22356        c.estrategia = Some(RestartStrategy::OneForOne);
22357        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22358        let via_standalone = crate::LayoutError::supervisor_slots_on_non_supervisor(
22359            &c,
22360            c.declared_supervisor_slots(),
22361        );
22362        assert_eq!(
22363            via_method, via_standalone,
22364            "Caixa::validate_kind_slot_coherence must surface the \
22365             supervisor-tree arm's diagnostic byte-equal to the \
22366             standalone LayoutError::supervisor_slots_on_non_supervisor \
22367             ctor on the same declared_supervisor_slots list",
22368        );
22369    }
22370
22371    #[test]
22372    fn validate_kind_slot_coherence_folds_servico_arm_matches_gate() {
22373        // Per-arm equivalence pin on the M2 Servico-runtime arm —
22374        // the third and last arm on the cross-family fold. A
22375        // non-Servico caixa carrying a declared M2 slot (a `:kind
22376        // Biblioteca` fixture with `:limits` set — the smallest
22377        // possible M2 slot declaration on a foreign kind) surfaces
22378        // the same [`crate::LayoutError::ServicoSlotsOnNonServico`]
22379        // variant through both dispatches. The three arms together
22380        // enumerate every typed-slot family the substrate carries
22381        // whose "declared but ignored" footgun is gated at the
22382        // layout altitude by a `{ caixa, kind, slots }` wrap variant,
22383        // so the per-arm pins collectively cover the whole
22384        // cross-family kind-coherence axis.
22385        use crate::limits::LimitsSpec;
22386        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22387        c.kind = CaixaKind::Biblioteca;
22388        c.limits = Some(LimitsSpec {
22389            memory: Some(64 * 1024 * 1024),
22390            fuel: None,
22391            wall_clock: None,
22392            cpu: None,
22393        });
22394        let via_method = c.validate_kind_slot_coherence().unwrap_err();
22395        let via_standalone =
22396            crate::LayoutError::servico_slots_on_non_servico(&c, c.declared_servico_slots());
22397        assert_eq!(
22398            via_method, via_standalone,
22399            "Caixa::validate_kind_slot_coherence must surface the M2 \
22400             Servico-runtime arm's diagnostic byte-equal to the \
22401             standalone LayoutError::servico_slots_on_non_servico ctor \
22402             on the same declared_servico_slots list",
22403        );
22404    }
22405
22406    #[test]
22407    fn validate_kind_slot_coherence_mesh_arm_fires_before_supervisor_arm() {
22408        // Cross-arm ordering pin between the first two arms of the
22409        // fold: a fixture carrying BOTH a declared M3 mesh slot
22410        // (`:membros`) AND a declared supervisor-tree slot
22411        // (`:estrategia`) on a foreign kind (a `:kind Servico` here —
22412        // foreign to both the Aplicacao arm and the Supervisor arm)
22413        // surfaces the M3 mesh diagnostic first through the compound
22414        // gate. Pins the pre-fold layout wire-up's canonical
22415        // diagnostic sequence (mesh → supervisor → servico) as a
22416        // property of the substrate primitive rather than a
22417        // convention of the layout call site. A silent reordering
22418        // regression at the primitive would surface here as a
22419        // wrong-variant match before landing at a downstream
22420        // consumer's diagnostic-ordering expectation.
22421        use crate::aplicacao::Membro;
22422        use crate::supervisor::RestartStrategy;
22423        let mut c = bare_servico_fixture("demo");
22424        c.membros = vec![Membro {
22425            caixa: "cart".into(),
22426            versao: "^0.1".into(),
22427        }];
22428        c.estrategia = Some(RestartStrategy::OneForOne);
22429        let err = c.validate_kind_slot_coherence().unwrap_err();
22430        assert!(
22431            matches!(err, crate::LayoutError::MeshSlotsOnNonAplicacao { .. }),
22432            "expected MeshSlotsOnNonAplicacao to fire before \
22433             SupervisorSlotsOnNonSupervisor under the canonical \
22434             mesh → supervisor → servico order, got {err:?}",
22435        );
22436    }
22437
22438    #[test]
22439    fn validate_kind_slot_coherence_supervisor_arm_fires_before_servico_arm() {
22440        // Cross-arm ordering pin between the second and third arms
22441        // of the fold: a fixture carrying BOTH a declared
22442        // supervisor-tree slot (`:estrategia`) AND a declared M2 slot
22443        // (`:limits`) on a kind foreign to both (a `:kind Biblioteca`
22444        // here — foreign to both the Supervisor and the Servico
22445        // arms) surfaces the supervisor-tree diagnostic first
22446        // through the compound gate. Together with the peer
22447        // `_mesh_arm_fires_before_supervisor_arm` pin above this
22448        // pins the whole three-arm canonical order (mesh →
22449        // supervisor → servico) at the substrate primitive.
22450        use crate::limits::LimitsSpec;
22451        use crate::supervisor::RestartStrategy;
22452        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22453        c.kind = CaixaKind::Biblioteca;
22454        c.estrategia = Some(RestartStrategy::OneForOne);
22455        c.limits = Some(LimitsSpec {
22456            memory: Some(64 * 1024 * 1024),
22457            fuel: None,
22458            wall_clock: None,
22459            cpu: None,
22460        });
22461        let err = c.validate_kind_slot_coherence().unwrap_err();
22462        assert!(
22463            matches!(
22464                err,
22465                crate::LayoutError::SupervisorSlotsOnNonSupervisor { .. }
22466            ),
22467            "expected SupervisorSlotsOnNonSupervisor to fire before \
22468             ServicoSlotsOnNonServico under the canonical mesh → \
22469             supervisor → servico order, got {err:?}",
22470        );
22471    }
22472
22473    #[test]
22474    fn validate_kind_slot_coherence_accepts_owner_kind_on_every_arm() {
22475        // Positive control on the identity-element arm: the owner
22476        // kind of each typed-slot family passes the compound gate
22477        // even when it declares the full slot set that family owns.
22478        // Aplicacao with `:membros` populated passes the mesh arm;
22479        // Supervisor with `:estrategia` populated passes the
22480        // supervisor arm; Servico with `:limits` populated passes
22481        // the servico arm. Pins the fold's identity element on
22482        // every owner kind — a silent regression that dropped the
22483        // paired `!kind().is_<owner>()` short-circuit guard would
22484        // surface here as a false-positive rejection of every
22485        // native-slot declaration. Peer with the
22486        // `validate_<kind>_shape_accepts_non_<kind>_kind` identity-
22487        // element pins on the sibling per-Caixa compound gates.
22488        use crate::aplicacao::{Membro, Placement, PlacementStrategy};
22489        use crate::limits::LimitsSpec;
22490        use crate::supervisor::{ChildSpec, RestartPolicy, RestartStrategy};
22491
22492        let mut apli = Caixa::from_lisp(&Caixa::template("app")).unwrap();
22493        apli.kind = CaixaKind::Aplicacao;
22494        apli.bibliotecas = vec![];
22495        apli.membros = vec![Membro {
22496            caixa: "cart".into(),
22497            versao: "^0.1".into(),
22498        }];
22499        apli.placement = Some(Placement {
22500            estrategia: PlacementStrategy::SingleNode,
22501            clusters: vec!["rio".into()],
22502            shard_key: None,
22503            affinity: None,
22504        });
22505        apli.validate_kind_slot_coherence().expect(
22506            "an :kind Aplicacao caixa with declared M3 mesh slots must \
22507             pass the compound gate — Aplicacao is the mesh-slot family's \
22508             owner kind and the fold's identity element on that arm",
22509        );
22510
22511        let mut sup = Caixa::from_lisp(&Caixa::template("sup")).unwrap();
22512        sup.kind = CaixaKind::Supervisor;
22513        sup.bibliotecas = vec![];
22514        sup.estrategia = Some(RestartStrategy::OneForOne);
22515        sup.children = vec![ChildSpec {
22516            caixa: "worker".into(),
22517            versao: "^0.1".into(),
22518            restart: RestartPolicy::Permanent,
22519        }];
22520        sup.validate_kind_slot_coherence().expect(
22521            "an :kind Supervisor caixa with declared supervisor-tree slots \
22522             must pass the compound gate — Supervisor is the \
22523             supervisor-slot family's owner kind and the fold's identity \
22524             element on that arm",
22525        );
22526
22527        let mut svc = bare_servico_fixture("svc");
22528        svc.limits = Some(LimitsSpec {
22529            memory: Some(64 * 1024 * 1024),
22530            fuel: None,
22531            wall_clock: None,
22532            cpu: None,
22533        });
22534        svc.validate_kind_slot_coherence().expect(
22535            "an :kind Servico caixa with declared M2 slots must pass the \
22536             compound gate — Servico is the M2-slot family's owner kind \
22537             and the fold's identity element on that arm",
22538        );
22539    }
22540
22541    #[test]
22542    fn validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind() {
22543        // Positive control on the second identity-element arm: a
22544        // bare caixa (no declared typed slots) passes the compound
22545        // gate on every kind. Pins the fold's identity element on
22546        // the empty-slot axis — the paired `Vec::is_empty` short-
22547        // circuit guard fires before the wrap dispatch on all three
22548        // arms, so a bare caixa of any kind surfaces no diagnostic.
22549        // A silent regression that dropped the emptiness guard
22550        // would surface here as a false-positive rejection of every
22551        // no-slot caixa across the whole kind axis.
22552        for kind in CaixaKind::ALL {
22553            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22554            c.kind = *kind;
22555            c.bibliotecas = vec![];
22556            c.validate_kind_slot_coherence().unwrap_or_else(|err| {
22557                panic!(
22558                    "a bare :kind {kind:?} caixa (no declared typed slots) \
22559                     must pass the compound gate — the fold's identity \
22560                     element on the empty-slot axis is the paired \
22561                     Vec::is_empty short-circuit guard, got {err:?}",
22562                )
22563            });
22564        }
22565    }
22566
22567    #[test]
22568    fn run_kind_owned_slot_family_gate_owner_kind_short_circuits_before_accumulator() {
22569        // Fail-before-pass-after identity-element pin on the owner-kind
22570        // arm of the substrate primitive: on a caixa whose kind IS the
22571        // owner of the family named by `is_owner`, the primitive
22572        // short-circuits before dispatching `accumulator` — pinned here
22573        // by a poison-pill accumulator that panics on call. If a
22574        // regression drops the `is_owner` short-circuit and always
22575        // invokes the accumulator, the poison panic surfaces here
22576        // rather than a spurious pass. Byte-equal to the pre-lift
22577        // `if !self.kind().is_<owner>() { … }` outer guard's
22578        // short-circuit at the pre-fold layout call site.
22579        let c = bare_servico_fixture("demo");
22580        c.run_kind_owned_slot_family_gate(
22581            CaixaKind::is_servico,
22582            |_| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking accumulator on the owner kind"),
22583            |_, _| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking wrap on the owner kind"),
22584        )
22585        .expect(
22586            "the owner kind of a slot family must pass the substrate \
22587             primitive as the fold's identity element on the outer \
22588             is_owner guard, without invoking accumulator or wrap",
22589        );
22590    }
22591
22592    #[test]
22593    fn run_kind_owned_slot_family_gate_empty_accumulator_short_circuits_before_wrap() {
22594        // Fail-before-pass-after identity-element pin on the empty-
22595        // accumulator arm: on a non-owner kind whose per-family
22596        // accumulator yields no declared slot, the primitive short-
22597        // circuits before dispatching `wrap` — pinned here by a
22598        // poison-pill wrap that panics on call. Byte-equal to the
22599        // pre-lift `if !<slots>.is_empty() { … }` inner emptiness
22600        // guard's short-circuit at the pre-fold layout call site.
22601        let c = bare_servico_fixture("demo");
22602        c.run_kind_owned_slot_family_gate(
22603            CaixaKind::is_aplicacao,
22604            Caixa::declared_mesh_slots,
22605            |_, _| panic!("run_kind_owned_slot_family_gate must short-circuit before invoking wrap on an empty accumulator"),
22606        )
22607        .expect(
22608            "a non-owner kind carrying no declared slot in the family \
22609             must pass the substrate primitive as the fold's identity \
22610             element on the inner emptiness guard, without invoking \
22611             wrap",
22612        );
22613    }
22614
22615    #[test]
22616    fn run_kind_owned_slot_family_gate_non_owner_non_empty_wraps_verbatim() {
22617        // Equivalence pin on the refusal arm: on a non-owner kind
22618        // whose accumulator yields a non-empty slot list, the primitive
22619        // returns the caller-supplied wrap byte-equal to the direct
22620        // ctor dispatch on the same `(caixa, slots)` pair. Pins the
22621        // three-argument route through — `is_owner` fires false, the
22622        // accumulator produces the slot list, and the wrap ctor
22623        // receives verbatim what a direct dispatch would receive.
22624        // Sibling of the peer per-arm equivalence pins on
22625        // [`Caixa::validate_kind_slot_coherence`].
22626        use crate::aplicacao::Membro;
22627        let mut c = bare_servico_fixture("demo");
22628        c.membros = vec![Membro {
22629            caixa: "cart".into(),
22630            versao: "^0.1".into(),
22631        }];
22632        let via_primitive = c
22633            .run_kind_owned_slot_family_gate(
22634                CaixaKind::is_aplicacao,
22635                Caixa::declared_mesh_slots,
22636                crate::LayoutError::mesh_slots_on_non_aplicacao,
22637            )
22638            .unwrap_err();
22639        let via_direct =
22640            crate::LayoutError::mesh_slots_on_non_aplicacao(&c, c.declared_mesh_slots());
22641        assert_eq!(
22642            via_primitive, via_direct,
22643            "Caixa::run_kind_owned_slot_family_gate must route the \
22644             non-owner-kind + non-empty-accumulator arm through the \
22645             caller-supplied wrap byte-equal to the direct ctor \
22646             dispatch on the same (caixa, slots) pair",
22647        );
22648    }
22649
22650    #[test]
22651    fn validate_kind_slot_coherence_routes_each_arm_through_run_kind_owned_slot_family_gate() {
22652        // Cross-primitive routing pin: every arm of the compound gate
22653        // [`Caixa::validate_kind_slot_coherence`] routes through the
22654        // substrate primitive [`Caixa::run_kind_owned_slot_family_gate`]
22655        // on its `(is_owner, accumulator, wrap)` triple. A silent
22656        // regression that de-folded one arm and re-inlined the four-
22657        // line block would surface here as a mismatch between the
22658        // compound-gate error and the direct-primitive-dispatch error
22659        // on the same fixture. Sibling of the peer
22660        // `probe_declared_entries_routes_miss_arm_through_probe_declared_entry`
22661        // cross-primitive routing pin on the layout-pipeline
22662        // existence-probe axis.
22663        use crate::aplicacao::Membro;
22664        use crate::limits::LimitsSpec;
22665        use crate::supervisor::RestartStrategy;
22666
22667        // Mesh arm — non-Aplicacao carrying a declared M3 slot.
22668        let mut mesh = bare_servico_fixture("demo");
22669        mesh.membros = vec![Membro {
22670            caixa: "cart".into(),
22671            versao: "^0.1".into(),
22672        }];
22673        let via_compound = mesh.validate_kind_slot_coherence().unwrap_err();
22674        let via_primitive = mesh
22675            .run_kind_owned_slot_family_gate(
22676                CaixaKind::is_aplicacao,
22677                Caixa::declared_mesh_slots,
22678                crate::LayoutError::mesh_slots_on_non_aplicacao,
22679            )
22680            .unwrap_err();
22681        assert_eq!(
22682            via_compound, via_primitive,
22683            "validate_kind_slot_coherence's mesh arm must route \
22684             byte-equal through the run_kind_owned_slot_family_gate \
22685             substrate primitive",
22686        );
22687
22688        // Supervisor arm — non-Supervisor carrying a declared
22689        // supervisor-tree slot on a kind foreign to both the Aplicacao
22690        // arm and this one.
22691        let mut sup = bare_servico_fixture("demo");
22692        sup.estrategia = Some(RestartStrategy::OneForOne);
22693        let via_compound = sup.validate_kind_slot_coherence().unwrap_err();
22694        let via_primitive = sup
22695            .run_kind_owned_slot_family_gate(
22696                CaixaKind::is_supervisor,
22697                Caixa::declared_supervisor_slots,
22698                crate::LayoutError::supervisor_slots_on_non_supervisor,
22699            )
22700            .unwrap_err();
22701        assert_eq!(
22702            via_compound, via_primitive,
22703            "validate_kind_slot_coherence's supervisor arm must route \
22704             byte-equal through the run_kind_owned_slot_family_gate \
22705             substrate primitive",
22706        );
22707
22708        // Servico arm — non-Servico carrying a declared M2 slot on a
22709        // kind foreign to every prior arm (Biblioteca — foreign to
22710        // both the Aplicacao mesh arm and the Supervisor supervisor
22711        // arm and the Servico M2 arm).
22712        let mut svc = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22713        svc.kind = CaixaKind::Biblioteca;
22714        svc.limits = Some(LimitsSpec {
22715            memory: Some(64 * 1024 * 1024),
22716            fuel: None,
22717            wall_clock: None,
22718            cpu: None,
22719        });
22720        let via_compound = svc.validate_kind_slot_coherence().unwrap_err();
22721        let via_primitive = svc
22722            .run_kind_owned_slot_family_gate(
22723                CaixaKind::is_servico,
22724                Caixa::declared_servico_slots,
22725                crate::LayoutError::servico_slots_on_non_servico,
22726            )
22727            .unwrap_err();
22728        assert_eq!(
22729            via_compound, via_primitive,
22730            "validate_kind_slot_coherence's servico arm must route \
22731             byte-equal through the run_kind_owned_slot_family_gate \
22732             substrate primitive",
22733        );
22734    }
22735
22736    #[test]
22737    fn validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate() {
22738        // Fail-before-pass-after per-arm equivalence pin on the
22739        // Supervisor no-code arm of the reciprocal code-surface
22740        // fold: a `:kind Supervisor` caixa carrying a declared
22741        // `:bibliotecas` entry (the smallest possible code-surface
22742        // declaration on a no-code kind) surfaces the same
22743        // [`crate::LayoutError::SupervisorOwnsCode`] variant
22744        // through both the compound gate
22745        // [`Caixa::validate_no_code_kind_coherence`] and the
22746        // standalone constructor
22747        // [`crate::LayoutError::supervisor_owns_code`]. Pins the
22748        // fold — a silent regression that de-folded the Supervisor
22749        // arm would surface here as a mismatch between the two
22750        // dispatches. Sibling in shape to the peer
22751        // `validate_kind_slot_coherence_folds_supervisor_arm_matches_gate`
22752        // per-arm equivalence pin on the cross-family
22753        // typed-slot-coherence fold.
22754        let mut c = Caixa::from_lisp(&Caixa::template("sup")).unwrap();
22755        c.kind = CaixaKind::Supervisor;
22756        c.bibliotecas = vec!["lib/sup.lisp".into()];
22757        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22758        let via_standalone = crate::LayoutError::supervisor_owns_code(&c);
22759        assert_eq!(
22760            via_method, via_standalone,
22761            "Caixa::validate_no_code_kind_coherence must surface the \
22762             Supervisor arm's diagnostic byte-equal to the standalone \
22763             LayoutError::supervisor_owns_code ctor",
22764        );
22765    }
22766
22767    #[test]
22768    fn validate_no_code_kind_coherence_folds_aplicacao_arm_matches_gate() {
22769        // Per-arm equivalence pin on the Aplicacao no-code arm —
22770        // the sibling of the Supervisor arm on the code-surface
22771        // fold. A `:kind Aplicacao` caixa carrying a declared
22772        // `:exe` entry surfaces the same
22773        // [`crate::LayoutError::AplicacaoOwnsCode`] variant through
22774        // both dispatches. Uses the `:exe` code-surface axis (a
22775        // second axis distinct from the Supervisor arm's
22776        // `:bibliotecas` fixture) so the three per-arm pins
22777        // collectively exercise every arm of the `has_code`
22778        // disjunction (`:bibliotecas || :exe || :servicos`).
22779        let mut c = Caixa::from_lisp(&Caixa::template("app")).unwrap();
22780        c.kind = CaixaKind::Aplicacao;
22781        c.bibliotecas = vec![];
22782        c.exe = vec!["exe/app".into()];
22783        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22784        let via_standalone = crate::LayoutError::aplicacao_owns_code(&c);
22785        assert_eq!(
22786            via_method, via_standalone,
22787            "Caixa::validate_no_code_kind_coherence must surface the \
22788             Aplicacao arm's diagnostic byte-equal to the standalone \
22789             LayoutError::aplicacao_owns_code ctor",
22790        );
22791    }
22792
22793    #[test]
22794    fn validate_no_code_kind_coherence_folds_acao_arm_matches_gate() {
22795        // Per-arm equivalence pin on the Acao no-code arm — the
22796        // third and last arm on the code-surface fold. A `:kind
22797        // Acao` caixa carrying a declared `:servicos` entry
22798        // surfaces the same [`crate::LayoutError::AcaoOwnsCode`]
22799        // variant through both dispatches. Uses the `:servicos`
22800        // code-surface axis (the third distinct axis of the
22801        // `has_code` disjunction) so the three per-arm pins
22802        // collectively cover every arm of the code-surface
22803        // disjunction plus every no-code kind of the arm
22804        // dispatch.
22805        let mut c = Caixa::from_lisp(&Caixa::template("acao")).unwrap();
22806        c.kind = CaixaKind::Acao;
22807        c.bibliotecas = vec![];
22808        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
22809        let via_method = c.validate_no_code_kind_coherence().unwrap_err();
22810        let via_standalone = crate::LayoutError::acao_owns_code(&c);
22811        assert_eq!(
22812            via_method, via_standalone,
22813            "Caixa::validate_no_code_kind_coherence must surface the \
22814             Acao arm's diagnostic byte-equal to the standalone \
22815             LayoutError::acao_owns_code ctor",
22816        );
22817    }
22818
22819    #[test]
22820    fn validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis() {
22821        // Positive control on the code-owning-kind identity
22822        // element: each of the three code-owning kinds
22823        // (`Biblioteca` owning `:bibliotecas`, `Binario` owning
22824        // `:exe`, `Servico` owning `:servicos`) passes the
22825        // compound gate cleanly when it declares its native code
22826        // surface. Pins the fold's second identity element — the
22827        // paired per-arm `is_<no-code-kind>()` short-circuit
22828        // fires on every code-owning kind, so a caixa with any
22829        // native code declaration on its owner kind surfaces no
22830        // diagnostic. A silent regression that dropped the paired
22831        // `is_<no-code-kind>()` short-circuit guard on any arm
22832        // would surface here as a false-positive rejection of the
22833        // corresponding owner kind. Peer with the
22834        // `validate_kind_slot_coherence_accepts_owner_kind_on_every_arm`
22835        // identity-element pin on the sibling cross-family fold.
22836        let mut bib = Caixa::from_lisp(&Caixa::template("bib")).unwrap();
22837        bib.kind = CaixaKind::Biblioteca;
22838        bib.bibliotecas = vec!["lib/bib.lisp".into()];
22839        bib.validate_no_code_kind_coherence().expect(
22840            "a :kind Biblioteca caixa with declared :bibliotecas must pass \
22841             the compound gate — Biblioteca owns the :bibliotecas code surface",
22842        );
22843
22844        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
22845        bin.kind = CaixaKind::Binario;
22846        bin.bibliotecas = vec![];
22847        bin.exe = vec!["exe/bin".into()];
22848        bin.validate_no_code_kind_coherence().expect(
22849            "a :kind Binario caixa with declared :exe must pass the compound \
22850             gate — Binario owns the :exe code surface",
22851        );
22852
22853        let svc = bare_servico_fixture("svc");
22854        svc.validate_no_code_kind_coherence().expect(
22855            "a :kind Servico caixa with declared :servicos must pass the \
22856             compound gate — Servico owns the :servicos code surface",
22857        );
22858    }
22859
22860    #[test]
22861    fn validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind() {
22862        // Positive control on the has-no-code identity element:
22863        // a bare caixa (no declared code) passes the compound
22864        // gate on every kind — including the three no-code kinds
22865        // that would otherwise fire an OwnsCode diagnostic. Pins
22866        // the fold's first identity element — the paired
22867        // `!has_code` short-circuit fires before every per-arm
22868        // wrap dispatch, so a bare caixa of any kind surfaces no
22869        // diagnostic. A silent regression that dropped the
22870        // has_code guard would surface here as a false-positive
22871        // rejection of every no-code kind that declares no code.
22872        // Peer with the
22873        // `validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind`
22874        // identity-element pin on the sibling cross-family fold.
22875        for kind in CaixaKind::ALL {
22876            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22877            c.kind = *kind;
22878            c.bibliotecas = vec![];
22879            c.exe = vec![];
22880            c.servicos = vec![];
22881            c.validate_no_code_kind_coherence().unwrap_or_else(|err| {
22882                panic!(
22883                    "a bare :kind {kind:?} caixa (no declared code) must pass \
22884                     the compound gate — the fold's first identity element is \
22885                     the paired !has_code short-circuit, got {err:?}",
22886                )
22887            });
22888        }
22889    }
22890
22891    #[test]
22892    fn validate_ci_kind_coherence_folds_arm_matches_gate() {
22893        // Fail-before-pass-after per-arm equivalence pin on the
22894        // `:ci`-on-non-`Acao` arm: a `:kind Biblioteca` caixa
22895        // (the smallest non-`Acao` kind) carrying a declared
22896        // `:ci` slot surfaces the same
22897        // [`crate::LayoutError::CiOnNonAcao`] variant through the
22898        // compound gate [`Caixa::validate_ci_kind_coherence`] and
22899        // an inlined struct-literal wrap carrying `caixa.nome()`
22900        // + `caixa.kind()` verbatim. Pins the fold — a silent
22901        // regression that de-folded the arm would surface here as
22902        // a mismatch between the two dispatches. Sibling in shape
22903        // to the peer
22904        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
22905        // per-arm equivalence pin on the reciprocal
22906        // code-surface fold.
22907        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22908        c.kind = CaixaKind::Biblioteca;
22909        c.ci = Some(canteiro_types::CiRun {
22910            workspace: "pleme-io".into(),
22911            repo: "caixa".into(),
22912            nodes: vec![],
22913        });
22914        let via_method = c.validate_ci_kind_coherence().unwrap_err();
22915        let via_standalone = crate::LayoutError::CiOnNonAcao {
22916            caixa: c.nome().to_string(),
22917            kind: c.kind(),
22918        };
22919        assert_eq!(
22920            via_method, via_standalone,
22921            "Caixa::validate_ci_kind_coherence must surface the \
22922             :ci-on-non-Acao arm's diagnostic byte-equal to a \
22923             LayoutError::CiOnNonAcao struct literal carrying the \
22924             caixa's nome + kind",
22925        );
22926    }
22927
22928    #[test]
22929    fn validate_ci_kind_coherence_fold_names_offending_kind_on_every_non_acao_kind() {
22930        // Exhaustive per-kind sweep on the non-`Acao` arm: for each
22931        // of the five non-`Acao` kinds
22932        // (`Biblioteca` / `Binario` / `Servico` / `Supervisor` /
22933        // `Aplicacao`), a caixa carrying a declared `:ci` slot
22934        // surfaces the [`crate::LayoutError::CiOnNonAcao`]
22935        // variant naming the offending kind verbatim. A silent
22936        // regression that mistyped one arm's kind-projection
22937        // (e.g. always threading `CaixaKind::Biblioteca` regardless
22938        // of the caixa's actual kind) would surface here as a
22939        // mismatch on every kind past the first. Peer of the
22940        // `validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind`
22941        // exhaustive-sweep pin on the sibling code-surface fold.
22942        for kind in CaixaKind::ALL {
22943            if kind.is_acao() {
22944                continue;
22945            }
22946            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22947            c.kind = *kind;
22948            c.ci = Some(canteiro_types::CiRun {
22949                workspace: "pleme-io".into(),
22950                repo: "caixa".into(),
22951                nodes: vec![],
22952            });
22953            let err = c.validate_ci_kind_coherence().unwrap_err();
22954            match err {
22955                crate::LayoutError::CiOnNonAcao {
22956                    caixa: got_caixa,
22957                    kind: got_kind,
22958                } => {
22959                    assert_eq!(
22960                        got_caixa,
22961                        c.nome(),
22962                        "CiOnNonAcao must name the offending caixa's nome verbatim on kind {kind:?}",
22963                    );
22964                    assert_eq!(
22965                        got_kind, *kind,
22966                        "CiOnNonAcao must name the offending kind verbatim on kind {kind:?}",
22967                    );
22968                }
22969                other => panic!(
22970                    "expected CiOnNonAcao on :kind {kind:?} with declared :ci, got {other:?}",
22971                ),
22972            }
22973        }
22974    }
22975
22976    #[test]
22977    fn validate_ci_kind_coherence_accepts_acao_on_every_ci_shape() {
22978        // Positive control on the owner-kind identity element: an
22979        // `:kind Acao` caixa passes the coherence gate cleanly on
22980        // every `:ci` shape — the arm's paired
22981        // `!kind().is_acao()` short-circuit fires before the
22982        // dispatch, so the fold surfaces no diagnostic even on
22983        // fixtures whose `:ci` would fail the peer
22984        // [`Self::validate_acao_shape`] decompose gate (a
22985        // duplicate-node fixture, an unknown-dep fixture, a
22986        // cyclic fixture). Pins the fold's first identity element
22987        // — a silent regression that dropped the paired
22988        // `!kind().is_acao()` short-circuit guard would surface
22989        // here as a false-positive rejection of every `Acao`
22990        // caixa. Peer with the
22991        // `validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis`
22992        // identity-element pin on the sibling code-surface fold.
22993        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
22994        c.kind = CaixaKind::Acao;
22995        c.bibliotecas = vec![];
22996        c.ci = Some(canteiro_types::CiRun {
22997            workspace: "pleme-io".into(),
22998            repo: "caixa".into(),
22999            nodes: vec![],
23000        });
23001        c.validate_ci_kind_coherence().expect(
23002            "a :kind Acao caixa with declared :ci must pass the compound \
23003             coherence gate — Acao is the :ci-owning kind (a malformed \
23004             :ci on Acao surfaces via validate_acao_shape's decompose gate, \
23005             not via this kind-coherence gate)",
23006        );
23007    }
23008
23009    #[test]
23010    fn validate_ci_kind_coherence_accepts_absent_ci_on_every_kind() {
23011        // Positive control on the absent-`:ci` identity element:
23012        // a caixa with `ci = None` passes the coherence gate on
23013        // every kind — including `Acao`, whose absent `:ci`
23014        // fails a separate presence gate ([`crate::LayoutError::MissingCi`])
23015        // downstream at the layout altitude, not this coherence
23016        // gate. Pins the fold's second identity element — the
23017        // paired `ci().is_some()` short-circuit fires before every
23018        // per-arm dispatch, so a caixa with no declared `:ci`
23019        // surfaces no coherence diagnostic. A silent regression
23020        // that dropped the paired `ci().is_some()` short-circuit
23021        // would surface here as a false-positive rejection on
23022        // every non-`Acao` kind. Peer with the
23023        // `validate_no_code_kind_coherence_accepts_bare_caixa_on_every_kind`
23024        // identity-element pin on the sibling code-surface fold.
23025        for kind in CaixaKind::ALL {
23026            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23027            c.kind = *kind;
23028            c.ci = None;
23029            c.validate_ci_kind_coherence().unwrap_or_else(|err| {
23030                panic!(
23031                    "a :kind {kind:?} caixa with no declared :ci must pass \
23032                     the compound coherence gate — the fold's second identity \
23033                     element is the paired ci().is_some() short-circuit, got \
23034                     {err:?}",
23035                )
23036            });
23037        }
23038    }
23039
23040    #[test]
23041    fn validate_foreign_code_kind_coherence_folds_arm_matches_gate() {
23042        // Fail-before-pass-after equivalence pin on the compound
23043        // foreign-code-slot coherence fold: a `:kind Servico` caixa
23044        // carrying a declared `:exe` entry (the smallest possible
23045        // foreign-code-slot declaration on a code-running kind that
23046        // is not its owner — Servico owns `:servicos`, not `:exe`)
23047        // surfaces the same [`crate::LayoutError::ForeignCodeSlot`]
23048        // variant through both the compound gate
23049        // [`Caixa::validate_foreign_code_kind_coherence`] and the
23050        // standalone constructor
23051        // [`crate::LayoutError::foreign_code_slot`] dispatched on the
23052        // same `declared_foreign_code_slots` list. Pins the fold — a
23053        // silent regression that de-folded the arm would surface here
23054        // as a mismatch between the two dispatches. Sibling in shape
23055        // to the peer
23056        // `validate_kind_slot_coherence_folds_mesh_arm_matches_gate`
23057        // / `validate_ci_kind_coherence_folds_arm_matches_gate` /
23058        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
23059        // per-arm equivalence pins on the sibling kind-coherence folds.
23060        let mut c = bare_servico_fixture("demo");
23061        c.exe = vec!["exe/foreign".into()];
23062        let via_method = c.validate_foreign_code_kind_coherence().unwrap_err();
23063        let via_standalone =
23064            crate::LayoutError::foreign_code_slot(&c, c.declared_foreign_code_slots());
23065        assert_eq!(
23066            via_method, via_standalone,
23067            "Caixa::validate_foreign_code_kind_coherence must surface the \
23068             foreign-code-slot diagnostic byte-equal to the standalone \
23069             LayoutError::foreign_code_slot ctor on the same \
23070             declared_foreign_code_slots list",
23071        );
23072    }
23073
23074    #[test]
23075    fn validate_foreign_code_kind_coherence_exe_arm_precedes_servicos_arm() {
23076        // Cross-arm ordering pin on the fold's accumulator: a fixture
23077        // carrying BOTH a declared `:exe` AND a declared `:servicos`
23078        // on a kind foreign to both (a `:kind Biblioteca` here —
23079        // foreign to both the Binario arm and the Servico arm)
23080        // surfaces `:exe` first in the `ForeignCodeSlot`'s slots
23081        // list. Pins the canonical `:exe` → `:servicos` diagnostic
23082        // order [`Caixa::declared_foreign_code_slots`] establishes,
23083        // as a property of the substrate primitive rather than an
23084        // implicit accumulator convention. A silent reordering
23085        // regression at the accumulator would surface here as a
23086        // wrong-first-slot list before landing at a downstream
23087        // consumer's diagnostic-ordering expectation.
23088        let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23089        c.kind = CaixaKind::Biblioteca;
23090        c.exe = vec!["exe/demo".into()];
23091        c.servicos = vec!["servicos/demo.computeunit.yaml".into()];
23092        let err = c.validate_foreign_code_kind_coherence().unwrap_err();
23093        let crate::LayoutError::ForeignCodeSlot { slots, .. } = &err else {
23094            panic!("expected ForeignCodeSlot variant, got {err:?}");
23095        };
23096        assert!(
23097            slots.starts_with(":exe"),
23098            "expected the :exe arm to precede the :servicos arm in the \
23099             ForeignCodeSlot slots list under the canonical :exe → :servicos \
23100             order, got slots = {slots:?}",
23101        );
23102        assert!(
23103            slots.contains(":servicos"),
23104            "expected the :servicos arm to also fire in the ForeignCodeSlot \
23105             slots list on a fixture carrying both foreign code surfaces, \
23106             got slots = {slots:?}",
23107        );
23108    }
23109
23110    #[test]
23111    fn validate_foreign_code_kind_coherence_accepts_native_slot_on_owner_kind() {
23112        // Positive control on the native-slot identity element: each
23113        // code-surface slot's owner kind passes the fold trivially
23114        // when it declares only its native code surface. `:kind
23115        // Binario` with a declared `:exe` and no `:servicos` passes
23116        // (the `!requires_exe()` guard short-circuits the arm inside
23117        // [`Caixa::declared_foreign_code_slots`], so the accumulator
23118        // returns empty); `:kind Servico` with a declared `:servicos`
23119        // and no `:exe` passes for the mirror reason. Pins the fold's
23120        // native-slot identity element on both arms — a silent
23121        // regression that dropped either per-arm `!requires_<slot>()`
23122        // predicate would surface here as a false-positive rejection
23123        // of every native-slot declaration on its owner kind. Peer
23124        // with the
23125        // `validate_kind_slot_coherence_accepts_owner_kind_on_every_arm`
23126        // identity-element pin on the sibling cross-family fold.
23127        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23128        bin.kind = CaixaKind::Binario;
23129        bin.bibliotecas = vec![];
23130        bin.exe = vec!["exe/bin".into()];
23131        bin.servicos = vec![];
23132        bin.validate_foreign_code_kind_coherence().expect(
23133            "a :kind Binario caixa with a declared native :exe and no \
23134             :servicos must pass the compound coherence gate — Binario is \
23135             the :exe slot's owner kind and the fold's native-slot identity \
23136             element on that arm",
23137        );
23138
23139        let mut svc = bare_servico_fixture("svc");
23140        svc.exe = vec![];
23141        svc.validate_foreign_code_kind_coherence().expect(
23142            "a :kind Servico caixa with a declared native :servicos and no \
23143             :exe must pass the compound coherence gate — Servico is the \
23144             :servicos slot's owner kind and the fold's native-slot identity \
23145             element on that arm",
23146        );
23147    }
23148
23149    #[test]
23150    fn validate_foreign_code_kind_coherence_accepts_bare_caixa_on_every_kind() {
23151        // Positive control on the empty-slot identity element: a
23152        // bare caixa (no declared `:exe` and no declared `:servicos`)
23153        // passes the compound gate on every kind. Pins the fold's
23154        // identity element on the empty-accumulator axis — the outer
23155        // `is_empty` short-circuit fires before the wrap dispatch on
23156        // every kind, so a bare caixa of any kind surfaces no
23157        // foreign-code-slot diagnostic. A silent regression that
23158        // dropped the emptiness guard would surface here as a
23159        // false-positive rejection of every no-code-slot caixa
23160        // across the whole kind axis. Peer with the
23161        // `validate_kind_slot_coherence_accepts_bare_caixa_on_every_kind`
23162        // identity-element pin on the sibling cross-family fold.
23163        for kind in CaixaKind::ALL {
23164            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23165            c.kind = *kind;
23166            c.bibliotecas = vec![];
23167            c.exe = vec![];
23168            c.servicos = vec![];
23169            c.validate_foreign_code_kind_coherence()
23170                .unwrap_or_else(|err| {
23171                    panic!(
23172                        "a bare :kind {kind:?} caixa (no declared :exe / \
23173                         :servicos) must pass the compound coherence gate — \
23174                         the fold's identity element on the empty-accumulator \
23175                         axis is the outer Vec::is_empty short-circuit, got \
23176                         {err:?}",
23177                    )
23178                });
23179        }
23180    }
23181
23182    #[test]
23183    fn validate_required_kind_slot_folds_binario_arm_matches_gate() {
23184        // Fail-before-pass-after per-arm equivalence pin on the
23185        // `Binario` required-`:exe` arm of the required-slot fold:
23186        // a `:kind Binario` caixa carrying no declared `:exe` entry
23187        // surfaces the same
23188        // [`crate::LayoutError::BinarioWithoutExe`] variant through
23189        // both the compound gate
23190        // [`Caixa::validate_required_kind_slot`] and the standalone
23191        // constructor [`crate::LayoutError::binario_without_exe`].
23192        // Pins the fold — a silent regression that de-folded the
23193        // `Binario` arm would surface here as a mismatch between
23194        // the two dispatches. Sibling in shape to the peer
23195        // `validate_no_code_kind_coherence_folds_supervisor_arm_matches_gate`
23196        // per-arm equivalence pin on the reciprocal code-surface
23197        // fold.
23198        let mut c = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23199        c.kind = CaixaKind::Binario;
23200        c.bibliotecas = vec![];
23201        c.exe = vec![];
23202        let via_method = c.validate_required_kind_slot().unwrap_err();
23203        let via_standalone = crate::LayoutError::binario_without_exe(&c);
23204        assert_eq!(
23205            via_method, via_standalone,
23206            "Caixa::validate_required_kind_slot must surface the \
23207             Binario arm's diagnostic byte-equal to the standalone \
23208             LayoutError::binario_without_exe ctor",
23209        );
23210    }
23211
23212    #[test]
23213    fn validate_required_kind_slot_folds_servico_arm_matches_gate() {
23214        // Per-arm equivalence pin on the `Servico` required-
23215        // `:servicos` arm — the sibling of the Binario arm on the
23216        // required-slot fold. A `:kind Servico` caixa carrying no
23217        // declared `:servicos` entry surfaces the same
23218        // [`crate::LayoutError::ServicoWithoutServicos`] variant
23219        // through both dispatches.
23220        let mut c = Caixa::from_lisp(&Caixa::template("svc")).unwrap();
23221        c.kind = CaixaKind::Servico;
23222        c.bibliotecas = vec![];
23223        c.servicos = vec![];
23224        let via_method = c.validate_required_kind_slot().unwrap_err();
23225        let via_standalone = crate::LayoutError::servico_without_servicos(&c);
23226        assert_eq!(
23227            via_method, via_standalone,
23228            "Caixa::validate_required_kind_slot must surface the \
23229             Servico arm's diagnostic byte-equal to the standalone \
23230             LayoutError::servico_without_servicos ctor",
23231        );
23232    }
23233
23234    #[test]
23235    fn validate_required_kind_slot_folds_acao_arm_matches_gate() {
23236        // Per-arm equivalence pin on the `Acao` required-`:ci` arm
23237        // — the third and last arm on the required-slot fold. A
23238        // `:kind Acao` caixa carrying no declared `:ci` slot
23239        // surfaces the same [`crate::LayoutError::MissingCi`]
23240        // variant through both dispatches. The three per-arm pins
23241        // collectively cover every required-slot axis and every
23242        // owner kind of the arm dispatch.
23243        let mut c = Caixa::from_lisp(&Caixa::template("acao")).unwrap();
23244        c.kind = CaixaKind::Acao;
23245        c.bibliotecas = vec![];
23246        c.ci = None;
23247        let via_method = c.validate_required_kind_slot().unwrap_err();
23248        let via_standalone = crate::LayoutError::missing_ci(&c);
23249        assert_eq!(
23250            via_method, via_standalone,
23251            "Caixa::validate_required_kind_slot must surface the \
23252             Acao arm's diagnostic byte-equal to the standalone \
23253             LayoutError::missing_ci ctor",
23254        );
23255    }
23256
23257    #[test]
23258    fn validate_required_kind_slot_accepts_owner_kind_with_required_slot_present() {
23259        // Positive control on the owner-kind-with-slot-present
23260        // identity element: each of the three owner kinds
23261        // (`Binario` with a non-empty `:exe`, `Servico` with a
23262        // non-empty `:servicos`, `Acao` with `ci = Some(_)`)
23263        // passes the compound gate cleanly when it declares its
23264        // required slot. Pins the fold's second identity element
23265        // — the paired `is_empty` / `is_none` short-circuit fires
23266        // on every owner kind whose required slot is present, so
23267        // a caixa with its native required slot surfaces no
23268        // diagnostic. A silent regression that dropped the paired
23269        // `is_empty` / `is_none` short-circuit guard on any arm
23270        // would surface here as a false-positive rejection of the
23271        // corresponding owner kind. Peer with the
23272        // `validate_no_code_kind_coherence_accepts_owner_kind_on_every_code_axis`
23273        // identity-element pin on the sibling code-surface fold.
23274        let mut bin = Caixa::from_lisp(&Caixa::template("bin")).unwrap();
23275        bin.kind = CaixaKind::Binario;
23276        bin.bibliotecas = vec![];
23277        bin.exe = vec!["exe/bin".into()];
23278        bin.validate_required_kind_slot().expect(
23279            "a :kind Binario caixa with declared :exe must pass the \
23280             required-slot gate — Binario's required slot is present",
23281        );
23282
23283        let svc = bare_servico_fixture("svc");
23284        svc.validate_required_kind_slot().expect(
23285            "a :kind Servico caixa with declared :servicos must pass \
23286             the required-slot gate — Servico's required slot is present",
23287        );
23288
23289        let acao = acao_fixture("acao");
23290        acao.validate_required_kind_slot().expect(
23291            "a :kind Acao caixa with declared :ci must pass the \
23292             required-slot gate — Acao's required slot is present",
23293        );
23294    }
23295
23296    #[test]
23297    fn validate_required_kind_slot_accepts_non_owner_kinds() {
23298        // Positive control on the non-owner-kind identity element:
23299        // every kind that is not one of the three owner kinds
23300        // (`Binario` / `Servico` / `Acao`) passes the compound gate
23301        // trivially — each per-arm predicate is
23302        // `self.kind().requires_<slot>()`, which returns `true`
23303        // only for the owner kind of that arm, so a non-owner kind
23304        // short-circuits every per-arm dispatch. Bibliotheca,
23305        // Supervisor, and Aplicacao are the three non-owner kinds
23306        // this pin exercises — none of them owns a required slot in
23307        // this fold (`Biblioteca`'s `:bibliotecas` default-file
23308        // fallback stays on the layout-side `MissingLib` fs-oracle
23309        // gate outside this fold; `Supervisor`'s `:children` and
23310        // `Aplicacao`'s `:membros` are carried by
23311        // [`CaixaKind::requires_children`] /
23312        // [`CaixaKind::requires_membros`] without a paired
23313        // layout-side wire-up). A silent regression that swapped a
23314        // per-arm predicate for a non-`requires_*` guard would
23315        // surface here as a false-positive rejection of the
23316        // corresponding non-owner kind. Peer with the
23317        // `validate_ci_kind_coherence_accepts_absent_ci_on_every_kind`
23318        // identity-element pin on the sibling `:ci` fold.
23319        for kind in CaixaKind::ALL {
23320            if kind.requires_exe() || kind.requires_servicos() || kind.requires_ci() {
23321                continue;
23322            }
23323            let mut c = Caixa::from_lisp(&Caixa::template("demo")).unwrap();
23324            c.kind = *kind;
23325            c.bibliotecas = vec![];
23326            c.exe = vec![];
23327            c.servicos = vec![];
23328            c.ci = None;
23329            c.validate_required_kind_slot().unwrap_or_else(|err| {
23330                panic!(
23331                    "a :kind {kind:?} caixa (a non-owner kind on every \
23332                     required-slot arm) must pass the compound gate — the \
23333                     fold's identity element is the paired \
23334                     `self.kind().requires_<slot>()` short-circuit, got \
23335                     {err:?}",
23336                )
23337            });
23338        }
23339    }
23340
23341    // ── `manifest_code_path_slot_path_ctors!` — the paired `{ slot:
23342    //    &'static str, path: PathBuf }` two-slot envelope on
23343    //    `ManifestError`, strict sibling of the peer
23344    //    [`crate::behavior::behavior_slot_path_ctors!`] (67c31ec) on the
23345    //    sibling `BehaviorError` envelope's identical
23346    //    `{ slot: &'static str, path: PathBuf }` two-slot shape.
23347    //    Five-variant lift closing the five open-coded ctor sites
23348    //    remaining on the `:bibliotecas` / `:exe` / `:servicos`
23349    //    code-path-list value-shape trajectory this envelope carries.
23350
23351    #[test]
23352    fn code_path_absolute_ctor_matches_struct_literal_wrap() {
23353        let path = Path::new("/abs/lib/x.lisp");
23354        assert_eq!(
23355            ManifestError::code_path_absolute(":bibliotecas", path),
23356            ManifestError::CodePathAbsolute {
23357                slot: ":bibliotecas",
23358                path: path.to_path_buf(),
23359            },
23360            "generated code_path_absolute ctor must produce byte-equal \
23361             `ManifestError::CodePathAbsolute` to the pre-lift \
23362             struct-literal wrap on the same `(&'static str, &Path)` \
23363             fixture",
23364        );
23365    }
23366
23367    #[test]
23368    fn code_path_parent_escape_ctor_matches_struct_literal_wrap() {
23369        let path = Path::new("lib/../../etc/x.lisp");
23370        assert_eq!(
23371            ManifestError::code_path_parent_escape(":bibliotecas", path),
23372            ManifestError::CodePathParentEscape {
23373                slot: ":bibliotecas",
23374                path: path.to_path_buf(),
23375            },
23376            "generated code_path_parent_escape ctor must produce \
23377             byte-equal `ManifestError::CodePathParentEscape` to the \
23378             pre-lift struct-literal wrap on the same `(&'static str, \
23379             &Path)` fixture",
23380        );
23381    }
23382
23383    #[test]
23384    fn code_path_non_lisp_extension_ctor_matches_struct_literal_wrap() {
23385        let path = Path::new("lib/x.txt");
23386        assert_eq!(
23387            ManifestError::code_path_non_lisp_extension(":bibliotecas", path),
23388            ManifestError::CodePathNonLispExtension {
23389                slot: ":bibliotecas",
23390                path: path.to_path_buf(),
23391            },
23392            "generated code_path_non_lisp_extension ctor must produce \
23393             byte-equal `ManifestError::CodePathNonLispExtension` to \
23394             the pre-lift struct-literal wrap on the same \
23395             `(&'static str, &Path)` fixture",
23396        );
23397    }
23398
23399    #[test]
23400    fn code_path_non_computeunit_yaml_extension_ctor_matches_struct_literal_wrap() {
23401        let path = Path::new("servicos/x.yaml");
23402        assert_eq!(
23403            ManifestError::code_path_non_computeunit_yaml_extension(":servicos", path),
23404            ManifestError::CodePathNonComputeUnitYamlExtension {
23405                slot: ":servicos",
23406                path: path.to_path_buf(),
23407            },
23408            "generated code_path_non_computeunit_yaml_extension ctor \
23409             must produce byte-equal \
23410             `ManifestError::CodePathNonComputeUnitYamlExtension` to \
23411             the pre-lift struct-literal wrap on the same \
23412             `(&'static str, &Path)` fixture",
23413        );
23414    }
23415
23416    #[test]
23417    fn code_path_duplicate_ctor_matches_struct_literal_wrap() {
23418        let path = Path::new("lib/x.lisp");
23419        assert_eq!(
23420            ManifestError::code_path_duplicate(":bibliotecas", path),
23421            ManifestError::CodePathDuplicate {
23422                slot: ":bibliotecas",
23423                path: path.to_path_buf(),
23424            },
23425            "generated code_path_duplicate ctor must produce byte-equal \
23426             `ManifestError::CodePathDuplicate` to the pre-lift \
23427             struct-literal wrap on the same `(&'static str, &Path)` \
23428             fixture",
23429        );
23430    }
23431
23432    #[test]
23433    fn manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly() {
23434        // Cross-axis routing pin: sweep the two constructor input axes
23435        // (`slot: &'static str`, `path: &Path`) through non-default
23436        // fixtures against every generated arm in the
23437        // [`manifest_code_path_slot_path_ctors!`] macro, so any
23438        // wrapper-side lowercase / trim / truncate / canonicalization at
23439        // codegen time — or a silent field re-name away from the
23440        // canonical `slot` / `path` axes on any one variant, or a `slot`
23441        // axis silently rerouted through `.to_string()` instead of
23442        // passed as `&'static str` verbatim, or a `path` axis silently
23443        // rerouted through `.canonicalize()` / `PathBuf::from(<lossy
23444        // string>)` instead of `.to_path_buf()` — surfaces here rather
23445        // than at a downstream diagnostic-shape mismatch. Peer of the
23446        // sibling
23447        // [`crate::behavior::tests::behavior_slot_path_ctors_route_slot_and_path_through_uniformly`]
23448        // pin (67c31ec) on the sibling `BehaviorError` envelope's
23449        // identical two-slot family.
23450        //
23451        // The `path` fixture carries three distinguishing traits at
23452        // once: a non-`root/`-relative leading segment (`weird/`), a
23453        // `..` component (a canonicalization trap that would collapse
23454        // to `weird/x.lisp` under `.canonicalize()`), and a mixed-case
23455        // extension (a lowercase-normalization trap that would collapse
23456        // `.LISP` to `.lisp` under any `to_ascii_lowercase()` codegen)
23457        // so a routing regression on any one of the three trap axes
23458        // surfaces at assert time. Similarly the `slot` fixture
23459        // sweeps the three canonical code-path author-key literals
23460        // (`:bibliotecas` / `:exe` / `:servicos`) so a silent lookup
23461        // against a per-variant const roster would surface here.
23462        let path = Path::new("weird/../nested/x.LISP");
23463        let cases: [(ManifestError, ManifestError); 5] = [
23464            (
23465                ManifestError::code_path_absolute(":bibliotecas", path),
23466                ManifestError::CodePathAbsolute {
23467                    slot: ":bibliotecas",
23468                    path: path.to_path_buf(),
23469                },
23470            ),
23471            (
23472                ManifestError::code_path_parent_escape(":exe", path),
23473                ManifestError::CodePathParentEscape {
23474                    slot: ":exe",
23475                    path: path.to_path_buf(),
23476                },
23477            ),
23478            (
23479                ManifestError::code_path_non_lisp_extension(":servicos", path),
23480                ManifestError::CodePathNonLispExtension {
23481                    slot: ":servicos",
23482                    path: path.to_path_buf(),
23483                },
23484            ),
23485            (
23486                ManifestError::code_path_non_computeunit_yaml_extension(":bibliotecas", path),
23487                ManifestError::CodePathNonComputeUnitYamlExtension {
23488                    slot: ":bibliotecas",
23489                    path: path.to_path_buf(),
23490                },
23491            ),
23492            (
23493                ManifestError::code_path_duplicate(":exe", path),
23494                ManifestError::CodePathDuplicate {
23495                    slot: ":exe",
23496                    path: path.to_path_buf(),
23497                },
23498            ),
23499        ];
23500        for (via_ctor, via_struct_literal) in cases {
23501            assert_eq!(
23502                via_ctor, via_struct_literal,
23503                "manifest_code_path_slot_path_ctors!-generated ctor \
23504                 must pass `slot` verbatim onto the canonical \
23505                 `&'static str` `slot` field and route `path` through \
23506                 `.to_path_buf()` onto the canonical `PathBuf` `path` \
23507                 field — a field-rename, silent-conversion, or \
23508                 axis-swap regression surfaces here rather than at a \
23509                 downstream diagnostic-shape mismatch",
23510            );
23511        }
23512    }
23513
23514    // Per-variant equivalence pin for the [`ManifestError::code_path_empty`]
23515    // one-slot inherent constructor (see the paired doc-block above the impl
23516    // definition) — the constructor folds the uniform
23517    // `Self::CodePathEmpty { slot }` one-field struct-literal onto one
23518    // substrate primitive. The equivalence pin below (fail-before-pass-after
23519    // by construction — a byte-mismatched constructor body would trip this pin
23520    // first) locks the generated constructor to its struct-literal peer under
23521    // `PartialEq`, so the wire-up at
23522    // [`Caixa::validate_code_path_lists`]'s per-slot
23523    // [`PathShapeViolation::Empty`] arm on this variant produces a byte-equal
23524    // `ManifestError` to the pre-lift open-coded struct-literal. The
23525    // cross-axis pin that follows (`slot: &'static str` sweep over every
23526    // canonical `:bibliotecas` / `:exe` / `:servicos` code-path author-key
23527    // label) routes the constructor input axis verbatim (`slot` as
23528    // `&'static str` without conversion), so the fold does not silently
23529    // collapse onto a fixed `slot` value.
23530    //
23531    // Peer of the sibling `code_path_absolute_ctor_matches_struct_literal_wrap`
23532    // / `code_path_parent_escape_ctor_matches_struct_literal_wrap` /
23533    // `code_path_non_lisp_extension_ctor_matches_struct_literal_wrap` /
23534    // `code_path_non_computeunit_yaml_extension_ctor_matches_struct_literal_wrap`
23535    // / `code_path_duplicate_ctor_matches_struct_literal_wrap` /
23536    // `manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly`
23537    // equivalence + cross-axis pins the peer
23538    // [`manifest_code_path_slot_path_ctors!`] family (de11917) established on
23539    // the paired `{ slot: &'static str, path: PathBuf }` two-slot envelope of
23540    // the same `ManifestError` — the per-slot [`PathShapeViolation`] cascade
23541    // at [`Caixa::validate_code_path_lists`] now carries a substrate-primitive
23542    // equivalence pin at every arm rather than five pinned arms plus a
23543    // hand-written open-coded sixth. Mirror-symmetric sibling of the peer
23544    // [`crate::behavior::tests::empty_path_ctor_matches_struct_literal_wrap`]
23545    // / `empty_path_ctor_routes_slot_verbatim_across_every_on_star_key` pins
23546    // on the sibling M2 `:behavior` envelope's identical one-slot shape.
23547
23548    #[test]
23549    fn code_path_empty_ctor_matches_struct_literal_wrap() {
23550        let slot = ":bibliotecas";
23551        assert_eq!(
23552            ManifestError::code_path_empty(slot),
23553            ManifestError::CodePathEmpty { slot },
23554            "generated code_path_empty ctor must produce byte-equal \
23555             `ManifestError::CodePathEmpty` to the open-coded struct-literal \
23556             wrap on the same `&'static str` fixture",
23557        );
23558    }
23559
23560    #[test]
23561    fn code_path_empty_ctor_routes_slot_verbatim_across_every_code_path_key() {
23562        // Cross-axis pin: sweep the constructor's single input axis
23563        // (`slot: &'static str`) through every canonical code-path
23564        // author-key label the outer per-slot iterator at
23565        // [`Caixa::validate_code_path_lists`] threads through so any
23566        // wrapper-side lowercase / trim / truncate / fixed-slot substitution
23567        // on the one-field construction surfaces here rather than at a
23568        // downstream diagnostic-shape mismatch. Peer of the sibling
23569        // [`manifest_code_path_slot_path_ctors_route_slot_and_path_through_uniformly`]
23570        // cross-axis pin on the two-slot envelope of the same
23571        // `ManifestError` — extended here onto the one-slot envelope so
23572        // both slot-only and slot+path constructor input axes carry a
23573        // per-code-path-label sweep. Mirror-symmetric sibling of the peer
23574        // [`crate::behavior::tests::empty_path_ctor_routes_slot_verbatim_across_every_on_star_key`]
23575        // sweep on the sibling M2 `:behavior` envelope's identical one-slot
23576        // shape.
23577        for slot in [":bibliotecas", ":exe", ":servicos"] {
23578            assert_eq!(
23579                ManifestError::code_path_empty(slot),
23580                ManifestError::CodePathEmpty { slot },
23581            );
23582        }
23583    }
23584
23585    // ── `manifest_field_reason_ctors!` — the paired `{ <field>: String,
23586    //    reason: String }` two-slot envelope on `ManifestError`, direct
23587    //    sibling of the peer
23588    //    [`crate::aplicacao::aplicacao_field_reason_ctors!`] (981060b)
23589    //    on the M3 mesh `AplicacaoError` envelope's identical two-slot
23590    //    shape and of the peer [`crate::dep::dep_nome_axis_reason_ctors!`]
23591    //    (5621f8a) on the sibling `:deps` envelope's mirror-symmetric
23592    //    three-slot shape (the `nome` axis added at the per-dep-owned
23593    //    altitude). Ten-variant lift closing the ten open-coded ctor
23594    //    sites at the per-axis [`Caixa::validate_*`] cascade — the tenth
23595    //    (`restart_window_malformed => RestartWindowMalformed
23596    //    { restart_window }`) closes the last open-coded four-line
23597    //    `.map_err(|reason| ManifestError::RestartWindowMalformed
23598    //    { restart_window: s.to_string(), reason })` block at
23599    //    [`Caixa::validate_restart_window`] onto the same substrate
23600    //    primitive per typed variant.
23601
23602    #[test]
23603    fn nome_invalid_ctor_matches_struct_literal_wrap() {
23604        let nome = "cart-svc";
23605        let reason = "sample reason text";
23606        assert_eq!(
23607            ManifestError::nome_invalid(nome, reason),
23608            ManifestError::NomeInvalid {
23609                nome: nome.to_string(),
23610                reason: reason.to_string(),
23611            },
23612            "generated nome_invalid ctor must produce byte-equal \
23613             `ManifestError::NomeInvalid` to the pre-lift struct-literal \
23614             wrap on the same `(&str, &str)` fixture",
23615        );
23616    }
23617
23618    #[test]
23619    fn nome_chart_name_budget_exceeded_ctor_matches_struct_literal_wrap() {
23620        let nome = "a-very-long-cart-service-name";
23621        let reason = "sample reason text";
23622        assert_eq!(
23623            ManifestError::nome_chart_name_budget_exceeded(nome, reason),
23624            ManifestError::NomeChartNameBudgetExceeded {
23625                nome: nome.to_string(),
23626                reason: reason.to_string(),
23627            },
23628            "generated nome_chart_name_budget_exceeded ctor must produce \
23629             byte-equal `ManifestError::NomeChartNameBudgetExceeded` to \
23630             the pre-lift struct-literal wrap on the same `(&str, &str)` \
23631             fixture",
23632        );
23633    }
23634
23635    #[test]
23636    fn versao_invalid_ctor_matches_struct_literal_wrap() {
23637        let versao = "0.1";
23638        let reason = "sample reason text";
23639        assert_eq!(
23640            ManifestError::versao_invalid(versao, reason),
23641            ManifestError::VersaoInvalid {
23642                versao: versao.to_string(),
23643                reason: reason.to_string(),
23644            },
23645            "generated versao_invalid ctor must produce byte-equal \
23646             `ManifestError::VersaoInvalid` to the pre-lift \
23647             struct-literal wrap on the same `(&str, &str)` fixture",
23648        );
23649    }
23650
23651    #[test]
23652    fn etiqueta_invalid_ctor_matches_struct_literal_wrap() {
23653        let etiqueta = "MyKeyword";
23654        let reason = "sample reason text";
23655        assert_eq!(
23656            ManifestError::etiqueta_invalid(etiqueta, reason),
23657            ManifestError::EtiquetaInvalid {
23658                etiqueta: etiqueta.to_string(),
23659                reason: reason.to_string(),
23660            },
23661            "generated etiqueta_invalid ctor must produce byte-equal \
23662             `ManifestError::EtiquetaInvalid` to the pre-lift \
23663             struct-literal wrap on the same `(&str, &str)` fixture",
23664        );
23665    }
23666
23667    #[test]
23668    fn autor_invalid_ctor_matches_struct_literal_wrap() {
23669        let autor = "Ada Lovelace";
23670        let reason = "sample reason text";
23671        assert_eq!(
23672            ManifestError::autor_invalid(autor, reason),
23673            ManifestError::AutorInvalid {
23674                autor: autor.to_string(),
23675                reason: reason.to_string(),
23676            },
23677            "generated autor_invalid ctor must produce byte-equal \
23678             `ManifestError::AutorInvalid` to the pre-lift struct-literal \
23679             wrap on the same `(&str, &str)` fixture",
23680        );
23681    }
23682
23683    #[test]
23684    fn repositorio_invalid_ctor_matches_struct_literal_wrap() {
23685        let repositorio = "https://example.com/no-dot-git";
23686        let reason = "sample reason text";
23687        assert_eq!(
23688            ManifestError::repositorio_invalid(repositorio, reason),
23689            ManifestError::RepositorioInvalid {
23690                repositorio: repositorio.to_string(),
23691                reason: reason.to_string(),
23692            },
23693            "generated repositorio_invalid ctor must produce byte-equal \
23694             `ManifestError::RepositorioInvalid` to the pre-lift \
23695             struct-literal wrap on the same `(&str, &str)` fixture",
23696        );
23697    }
23698
23699    #[test]
23700    fn descricao_invalid_ctor_matches_struct_literal_wrap() {
23701        let descricao = "some description";
23702        let reason = "sample reason text";
23703        assert_eq!(
23704            ManifestError::descricao_invalid(descricao, reason),
23705            ManifestError::DescricaoInvalid {
23706                descricao: descricao.to_string(),
23707                reason: reason.to_string(),
23708            },
23709            "generated descricao_invalid ctor must produce byte-equal \
23710             `ManifestError::DescricaoInvalid` to the pre-lift \
23711             struct-literal wrap on the same `(&str, &str)` fixture",
23712        );
23713    }
23714
23715    #[test]
23716    fn licenca_invalid_ctor_matches_struct_literal_wrap() {
23717        let licenca = "not-an-spdx";
23718        let reason = "sample reason text";
23719        assert_eq!(
23720            ManifestError::licenca_invalid(licenca, reason),
23721            ManifestError::LicencaInvalid {
23722                licenca: licenca.to_string(),
23723                reason: reason.to_string(),
23724            },
23725            "generated licenca_invalid ctor must produce byte-equal \
23726             `ManifestError::LicencaInvalid` to the pre-lift \
23727             struct-literal wrap on the same `(&str, &str)` fixture",
23728        );
23729    }
23730
23731    #[test]
23732    fn edicao_invalid_ctor_matches_struct_literal_wrap() {
23733        let edicao = "26";
23734        let reason = "sample reason text";
23735        assert_eq!(
23736            ManifestError::edicao_invalid(edicao, reason),
23737            ManifestError::EdicaoInvalid {
23738                edicao: edicao.to_string(),
23739                reason: reason.to_string(),
23740            },
23741            "generated edicao_invalid ctor must produce byte-equal \
23742             `ManifestError::EdicaoInvalid` to the pre-lift \
23743             struct-literal wrap on the same `(&str, &str)` fixture",
23744        );
23745    }
23746
23747    #[test]
23748    fn restart_window_malformed_ctor_matches_struct_literal_wrap() {
23749        let restart_window = "1.5s";
23750        let reason = "sample reason text";
23751        assert_eq!(
23752            ManifestError::restart_window_malformed(restart_window, reason),
23753            ManifestError::RestartWindowMalformed {
23754                restart_window: restart_window.to_string(),
23755                reason: reason.to_string(),
23756            },
23757            "generated restart_window_malformed ctor must produce byte-equal \
23758             `ManifestError::RestartWindowMalformed` to the pre-lift \
23759             struct-literal wrap on the same `(&str, &str)` fixture",
23760        );
23761    }
23762
23763    // Routing pin against the actual [`Caixa::validate_restart_window`]
23764    // wire-up: the codec surfaces its parse error as `Result<Duration, String>`,
23765    // and the pre-lift `.map_err(|reason| ManifestError::RestartWindowMalformed
23766    // { restart_window: s.to_string(), reason })` closure passed the owned
23767    // `String` verbatim onto the `reason: String` slot. The lifted
23768    // `restart_window_malformed(&str, impl Into<String>)` ctor must produce
23769    // byte-equal output on the same `(offending_value, owned_reason)` pair a
23770    // real parse-failure fixture surfaces, so a silent regression on the
23771    // owned-`String` axis (a future `reason` bound change dropping the
23772    // `Into<String>` route the owned reason threads through) surfaces here
23773    // rather than at a downstream diagnostic-shape drift.
23774    #[test]
23775    fn restart_window_malformed_ctor_matches_wire_up_owned_reason_shape() {
23776        let raw = "1.5s";
23777        let reason: String = crate::supervisor::duration_codec::parse(raw)
23778            .expect_err("fractional-seconds `1.5s` must fail the shared codec");
23779        assert_eq!(
23780            ManifestError::restart_window_malformed(raw, reason.clone()),
23781            ManifestError::RestartWindowMalformed {
23782                restart_window: raw.to_string(),
23783                reason: reason.clone(),
23784            },
23785            "generated restart_window_malformed ctor must accept the owned \
23786             `String` the [`crate::supervisor::duration_codec::parse`] parse-\
23787             error carrier surfaces (the exact shape the \
23788             [`Caixa::validate_restart_window`] `.map_err(|reason| ...)` \
23789             closure passes into it) and produce byte-equal \
23790             `ManifestError::RestartWindowMalformed` to the pre-lift \
23791             struct-literal wrap on the same `(offending_value, owned_reason)` \
23792             pair",
23793        );
23794    }
23795
23796    // Cross-family invariance pin — the ten sibling ctors all route
23797    // `reason: impl Into<String>` + `<field>: &str` verbatim onto their
23798    // respective typed variants through the shared
23799    // [`manifest_field_reason_ctors!`] macro. Sweeps three fixture
23800    // shapes for `reason` (`&str` literal, owned `String`, `format!(…)`
23801    // output — the three shapes every in-crate wire-up threads through:
23802    // the parser-shaped `String` every `Result<(), String>` predicate
23803    // returns, the `e.to_string()` owned `String` the
23804    // `semver::Version::parse` arm passes, and the literal-shape reason
23805    // the `EdicaoInvalid` direct arm passes) against every generated arm
23806    // so any per-arm wrapper transformation drift surfaces here rather
23807    // than at a downstream diagnostic-shape mismatch. Peer of the
23808    // sibling
23809    // [`crate::aplicacao::tests::aplicacao_field_reason_ctors_route_reason_through_into_uniformly`]
23810    // pin (981060b) on the sibling `AplicacaoError` envelope's identical
23811    // two-slot family.
23812    #[test]
23813    fn manifest_field_reason_ctors_route_reason_through_into_uniformly() {
23814        let via_literal = "literal reason text";
23815        let via_owned: String = String::from("literal reason text");
23816        let via_format = format!("{} reason text", "literal");
23817        assert_eq!(
23818            ManifestError::nome_invalid("n", via_literal),
23819            ManifestError::nome_invalid("n", via_owned.clone()),
23820        );
23821        assert_eq!(
23822            ManifestError::nome_invalid("n", via_literal),
23823            ManifestError::nome_invalid("n", via_format.clone()),
23824        );
23825        assert_eq!(
23826            ManifestError::nome_chart_name_budget_exceeded("n", via_literal),
23827            ManifestError::nome_chart_name_budget_exceeded("n", via_owned.clone()),
23828        );
23829        assert_eq!(
23830            ManifestError::versao_invalid("0.1", via_literal),
23831            ManifestError::versao_invalid("0.1", via_owned.clone()),
23832        );
23833        assert_eq!(
23834            ManifestError::etiqueta_invalid("k", via_literal),
23835            ManifestError::etiqueta_invalid("k", via_owned.clone()),
23836        );
23837        assert_eq!(
23838            ManifestError::autor_invalid("a", via_literal),
23839            ManifestError::autor_invalid("a", via_owned.clone()),
23840        );
23841        assert_eq!(
23842            ManifestError::repositorio_invalid("r", via_literal),
23843            ManifestError::repositorio_invalid("r", via_owned.clone()),
23844        );
23845        assert_eq!(
23846            ManifestError::descricao_invalid("d", via_literal),
23847            ManifestError::descricao_invalid("d", via_owned.clone()),
23848        );
23849        assert_eq!(
23850            ManifestError::licenca_invalid("l", via_literal),
23851            ManifestError::licenca_invalid("l", via_owned.clone()),
23852        );
23853        assert_eq!(
23854            ManifestError::edicao_invalid("26", via_literal),
23855            ManifestError::edicao_invalid("26", via_owned.clone()),
23856        );
23857        assert_eq!(
23858            ManifestError::edicao_invalid("26", via_literal),
23859            ManifestError::edicao_invalid("26", via_format.clone()),
23860        );
23861        assert_eq!(
23862            ManifestError::restart_window_malformed("1.5s", via_literal),
23863            ManifestError::restart_window_malformed("1.5s", via_owned),
23864        );
23865        assert_eq!(
23866            ManifestError::restart_window_malformed("1.5s", via_literal),
23867            ManifestError::restart_window_malformed("1.5s", via_format),
23868        );
23869    }
23870
23871    // Cross-arm routing pin — the ten sibling ctors accept both `&str`
23872    // (from the [`Caixa::nome`] / [`Caixa::versao`] / [`Caixa::repositorio`]
23873    // / [`Caixa::descricao`] / [`Caixa::licenca`] / [`Caixa::edicao`]
23874    // accessors that return `&str`) and `&String` (from the
23875    // [`Caixa::etiquetas`] / [`Caixa::autores`] slice iterators that yield
23876    // `&String`) at the `<field>: &str` parameter via Deref coercion. This
23877    // pin sweeps both call shapes against the two accessors' actual
23878    // wire-up postures so a future rebrand of the etiquetas / autores
23879    // slice-iterator type (a lift from `&[String]` to `&[Cow<'_, str>]`,
23880    // a `smol_str::SmolStr` per-entry swap) that silently broke the
23881    // Deref-coercion path surfaces at this pin rather than at a
23882    // recompile-time type-mismatch far from the ctor family.
23883    #[test]
23884    fn manifest_field_reason_ctors_accept_both_str_and_string_slice_iters() {
23885        let owned: String = String::from("MyKeyword");
23886        // `&str` literal — the canonical accessor-return shape
23887        // ([`Caixa::nome`] etc. yield `&str`).
23888        assert_eq!(
23889            ManifestError::etiqueta_invalid("MyKeyword", "r"),
23890            ManifestError::EtiquetaInvalid {
23891                etiqueta: "MyKeyword".to_string(),
23892                reason: "r".to_string(),
23893            },
23894        );
23895        // `&String` — the canonical slice-iterator-yield shape
23896        // ([`Caixa::etiquetas`] / [`Caixa::autores`] yield `&String`).
23897        assert_eq!(
23898            ManifestError::etiqueta_invalid(&owned, "r"),
23899            ManifestError::EtiquetaInvalid {
23900                etiqueta: owned.clone(),
23901                reason: "r".to_string(),
23902            },
23903        );
23904        // Both call shapes must produce byte-equal
23905        // [`ManifestError::EtiquetaInvalid`] values on the same
23906        // underlying `String`, so a wire-up threading `etiqueta: &String`
23907        // through the same ctor as a peer wire-up threading `nome: &str`
23908        // through it collapses onto one canonical shape.
23909        assert_eq!(
23910            ManifestError::etiqueta_invalid("MyKeyword", "r"),
23911            ManifestError::etiqueta_invalid(&owned, "r"),
23912        );
23913    }
23914
23915    // ── `manifest_field_only_ctors!` — the paired `{ <field>: String }`
23916    //    single-slot envelope on `ManifestError`, direct sibling of the
23917    //    peer [`crate::aplicacao::aplicacao_caixa_only_ctors!`] (d9f6867,
23918    //    `{ caixa: String }` on `AplicacaoError`) and
23919    //    [`crate::aplicacao::aplicacao_path_only_ctors!`] (3ba8de6,
23920    //    `{ path: String }` on `AplicacaoError`) on the M3 mesh envelope,
23921    //    of the peer [`crate::supervisor::supervisor_caixa_only_ctors!`]
23922    //    (db09650, `{ caixa: String }` on `SupervisorError`), and of the
23923    //    peer [`crate::dep::dep_nome_only_ctors!`] (792aa92,
23924    //    `{ nome: String }` on `DepError`) folds on their sibling
23925    //    envelopes. Two-variant lift closing the last two open-coded
23926    //    single-`String`-slot ctor sites at
23927    //    [`Caixa::validate_etiquetas`] and [`Caixa::validate_autores`].
23928
23929    #[test]
23930    fn etiqueta_duplicate_ctor_matches_struct_literal_wrap() {
23931        assert_eq!(
23932            ManifestError::etiqueta_duplicate("mesh"),
23933            ManifestError::EtiquetaDuplicate {
23934                etiqueta: "mesh".to_string(),
23935            },
23936            "generated etiqueta_duplicate ctor must produce byte-equal \
23937             `ManifestError::EtiquetaDuplicate` to the pre-lift \
23938             struct-literal wrap on the same `&str` fixture",
23939        );
23940    }
23941
23942    #[test]
23943    fn autor_duplicate_ctor_matches_struct_literal_wrap() {
23944        assert_eq!(
23945            ManifestError::autor_duplicate("pleme-io"),
23946            ManifestError::AutorDuplicate {
23947                autor: "pleme-io".to_string(),
23948            },
23949            "generated autor_duplicate ctor must produce byte-equal \
23950             `ManifestError::AutorDuplicate` to the pre-lift \
23951             struct-literal wrap on the same `&str` fixture",
23952        );
23953    }
23954
23955    #[test]
23956    fn manifest_field_only_ctors_route_field_through_to_string() {
23957        // Cross-axis pin: sweep the sole constructor input axis
23958        // (`<field>: &str`) through a non-default fixture value against
23959        // every generated arm in the [`manifest_field_only_ctors!`]
23960        // macro, so any wrapper-side lowercase / trim / truncate / silent
23961        // constant-substitution on the `<field>.to_string()` sole-field
23962        // construction surfaces here rather than at a downstream
23963        // diagnostic-shape mismatch. Peer of the sibling
23964        // [`crate::aplicacao::tests::aplicacao_caixa_only_ctors_route_caixa_through_to_string`]
23965        // (d9f6867) and
23966        // [`crate::aplicacao::tests::aplicacao_path_only_ctors_route_path_through_to_string`]
23967        // (3ba8de6) cross-axis pins on the peer `AplicacaoError`
23968        // single-`String`-slot envelopes.
23969        let value = "cache-v2";
23970        assert_eq!(
23971            ManifestError::etiqueta_duplicate(value),
23972            ManifestError::EtiquetaDuplicate {
23973                etiqueta: value.to_string(),
23974            },
23975        );
23976        assert_eq!(
23977            ManifestError::autor_duplicate(value),
23978            ManifestError::AutorDuplicate {
23979                autor: value.to_string(),
23980            },
23981        );
23982    }
23983
23984    #[test]
23985    fn manifest_field_only_ctors_accept_both_str_and_string_slice_iters() {
23986        // The two wire-up sites at [`Caixa::validate_etiquetas`] and
23987        // [`Caixa::validate_autores`] each thread a `&String` loop head
23988        // through the ctor via Deref coercion at the `<field>: &str`
23989        // parameter — this pin locks that call shape's byte-equality
23990        // against the direct `&str` shape so a future rebrand of the
23991        // `:etiquetas` / `:autores` slice-iterator type that silently
23992        // broke the Deref-coercion path surfaces here rather than at a
23993        // recompile-time type-mismatch far from the ctor family. Peer of
23994        // the sibling
23995        // [`manifest_field_reason_ctors_accept_both_str_and_string_slice_iters`]
23996        // pin on the peer two-slot `{ <field>: String, reason: String }`
23997        // envelope.
23998        let etiqueta: String = String::from("mesh");
23999        assert_eq!(
24000            ManifestError::etiqueta_duplicate("mesh"),
24001            ManifestError::etiqueta_duplicate(&etiqueta),
24002        );
24003        let autor: String = String::from("pleme-io");
24004        assert_eq!(
24005            ManifestError::autor_duplicate("pleme-io"),
24006            ManifestError::autor_duplicate(&autor),
24007        );
24008    }
24009
24010    #[test]
24011    fn dialeto_estrangeiro_ctor_matches_struct_literal_wrap() {
24012        // Byte-identity pin against the pre-lift open-coded
24013        // `Self::DialetoEstrangeiro { dialeto }` one-field struct-literal —
24014        // a future silent de-lift of [`Caixa::from_lisp`]'s foreign-dialect
24015        // wire-up back to an inline struct-literal (or a divergence between
24016        // the ctor's stored-field wrapping and the struct-literal shape
24017        // downstream consumers still read through `matches!`
24018        // destructuring) trips at caixa-core test time rather than at a
24019        // downstream `LeituraError::to_string()` diagnostic-shape drift on
24020        // a consumer far from the wire-up commit. Peer of the sibling
24021        // [`crate::dialeto::tests::cabeca_errada_ctor_matches_struct_literal_wrap`]
24022        // (38d5159) byte-identity pin the peer single-slot
24023        // [`crate::dialeto::DialetoError::cabeca_errada`] ctor carries.
24024        for dialeto in [
24025            crate::dialeto::CaixaDialeto::Molde,
24026            crate::dialeto::CaixaDialeto::MoldePosicional,
24027        ] {
24028            let via_ctor = LeituraError::dialeto_estrangeiro(dialeto);
24029            let via_struct_literal = LeituraError::DialetoEstrangeiro { dialeto };
24030            assert!(
24031                matches!(
24032                    (&via_ctor, &via_struct_literal),
24033                    (
24034                        LeituraError::DialetoEstrangeiro { dialeto: a },
24035                        LeituraError::DialetoEstrangeiro { dialeto: b },
24036                    ) if a == b && *a == dialeto
24037                ),
24038                "LeituraError::dialeto_estrangeiro({dialeto:?}) must \
24039                 byte-match the open-coded `LeituraError::DialetoEstrangeiro \
24040                 {{ dialeto: {dialeto:?} }}` struct-literal — a future \
24041                 silent de-lift back to the struct-literal, or a divergence \
24042                 in the field's stored shape, would surface here",
24043            );
24044            assert_eq!(
24045                via_ctor.to_string(),
24046                via_struct_literal.to_string(),
24047                "Display byte-string must be identical between the ctor \
24048                 and struct-literal forms — a divergence would mean the \
24049                 ctor wired the field through a different projection than \
24050                 the struct-literal, silently splitting the two paths' \
24051                 diagnostic shape. dialect: {dialeto:?}",
24052            );
24053        }
24054    }
24055
24056    #[test]
24057    fn dialeto_estrangeiro_routes_dialeto_verbatim_across_every_caixa_dialeto_arm() {
24058        // Boundary-covering fixture sweep on the sole
24059        // [`crate::dialeto::CaixaDialeto`] axis the variant carries —
24060        // every arm in [`crate::dialeto::CaixaDialeto::ALL`] (including the
24061        // non-[`crate::dialeto::CaixaDialeto::is_molde_family`] arms the
24062        // [`Caixa::from_lisp`] wire-up never reaches today, since the ctor
24063        // is a substrate primitive independent of any single caller's
24064        // dispatch gate) round-trips through the ctor byte-equal to the
24065        // input and byte-equal to the open-coded struct-literal wrap. Any
24066        // wrapper-side silent transformation (a `dialeto.normalize()`
24067        // rewrite, a `dialeto.into()` divergence, an accidental field
24068        // rebrand on the ctor body) surfaces at assert time rather than
24069        // at a downstream consumer that reads `err.dialeto` back and
24070        // gets a different arm than the one it stored. Peer of the sibling
24071        // [`crate::dialeto::tests::cabeca_errada_routes_encontrado_verbatim_across_boundary_inputs`]
24072        // (38d5159) boundary-sweep pin on the peer single-slot ctor.
24073        for &dialeto in crate::dialeto::CaixaDialeto::ALL {
24074            let via_ctor = LeituraError::dialeto_estrangeiro(dialeto);
24075            match via_ctor {
24076                LeituraError::DialetoEstrangeiro { dialeto: stored } => {
24077                    assert_eq!(
24078                        stored, dialeto,
24079                        "LeituraError::dialeto_estrangeiro({dialeto:?}) \
24080                         must route the input arm verbatim into the \
24081                         stored `dialeto:` field — any silent \
24082                         normalization on the ctor path would surface \
24083                         here rather than at a downstream consumer that \
24084                         branches on `err.dialeto`",
24085                    );
24086                }
24087                other => panic!(
24088                    "dialeto_estrangeiro({dialeto:?}) must construct the \
24089                     DialetoEstrangeiro variant; got: {other:?}"
24090                ),
24091            }
24092        }
24093    }
24094
24095    #[test]
24096    fn from_lisp_foreign_dialect_gate_routes_through_dialeto_estrangeiro_ctor() {
24097        // End-to-end pin refusing a silent regression that de-folds the
24098        // [`Caixa::from_lisp`] production wire-up back to
24099        // `Err(LeituraError::DialetoEstrangeiro { dialeto })` at the
24100        // foreign-dialect classification arm — for every arm in
24101        // [`crate::dialeto::CaixaDialeto::ALL`] the
24102        // [`crate::dialeto::CaixaDialeto::is_molde_family`] partition
24103        // returns `true` for (the [`crate::dialeto::CaixaDialeto::Molde`]
24104        // and [`crate::dialeto::CaixaDialeto::MoldePosicional`]
24105        // canonical two-arity closure), the observed
24106        // [`Caixa::from_lisp`] `Err` byte-equals the value returned by
24107        // `LeituraError::dialeto_estrangeiro(dialeto)`. Peer of the sibling
24108        // [`crate::dialeto::tests::classify_form_wrong_head_routes_through_cabeca_errada_ctor`]
24109        // (38d5159) end-to-end wire-up pin on the sibling
24110        // [`crate::dialeto::classify_form`] wrong-head gate.
24111        let fixtures: &[(crate::dialeto::CaixaDialeto, &str)] = &[
24112            (
24113                crate::dialeto::CaixaDialeto::Molde,
24114                r#"
24115                  (defcaixa
24116                    :name "base64"
24117                    :kind :Biblioteca
24118                    :ecosystem :rust-single-crate
24119                    :package {:name "base64" :version "0.22.1"})
24120                "#,
24121            ),
24122            (
24123                crate::dialeto::CaixaDialeto::MoldePosicional,
24124                r#"
24125                  (defcaixa todoku-go
24126                    :kind :Biblioteca
24127                    :ecosystem :go
24128                    :package {:name "todoku-go" :version "0.3.0"})
24129                "#,
24130            ),
24131        ];
24132
24133        for &(expected, src) in fixtures {
24134            let observed = Caixa::from_lisp(src.trim())
24135                .expect_err("foreign-dialect source must not parse as Pacote");
24136            let via_ctor = LeituraError::dialeto_estrangeiro(expected);
24137            assert!(
24138                matches!(
24139                    (&observed, &via_ctor),
24140                    (
24141                        LeituraError::DialetoEstrangeiro { dialeto: a },
24142                        LeituraError::DialetoEstrangeiro { dialeto: b },
24143                    ) if a == b && *a == expected
24144                ),
24145                "Caixa::from_lisp on {expected:?} source must byte-equal \
24146                 LeituraError::dialeto_estrangeiro({expected:?}) — a silent \
24147                 de-lift of the production wire-up back to the open-coded \
24148                 struct-literal, or a divergence between the ctor and the \
24149                 gate's construction shape, would surface here rather than \
24150                 at a downstream diagnostic consumer",
24151            );
24152            assert_eq!(
24153                observed.to_string(),
24154                via_ctor.to_string(),
24155                "from_lisp's observed `Err` and \
24156                 `dialeto_estrangeiro({expected:?})` must render the same \
24157                 Display byte-string — any drift means the two \
24158                 construction paths projected the same axis through \
24159                 different display shapes",
24160            );
24161        }
24162    }
24163}