Skip to main content

caixa_core/
render.rs

1//! Render-side helpers shared by every per-Servico renderer
2//! ([`caixa-helm`], [`caixa-flux`]) — the canonical place for "if the
3//! M2 typed slot is non-empty, emit its camelCase YAML fragment under
4//! the agreed key" patterns to live exactly once.
5//!
6//! Until this module landed both renderers carried an inline ~20-line
7//! block per render entry-point that:
8//!
9//! 1. Checked `caixa.limits.is_some() && !limits.is_empty()`.
10//! 2. Called `serde_yaml::to_value(limits).unwrap_or(Value::Null)` —
11//!    silently swallowing every serialization error as a `null`-shaped
12//!    fragment that would render as `limits: null` in the values block,
13//!    indistinguishable from "the author omitted the slot" downstream.
14//! 3. Inserted under the camelCase key `"limits"` with `or_insert`
15//!    semantics so explicit `spec.*` fields from the ComputeUnit YAML
16//!    take precedence over the manifest-derived overlay.
17//! 4. Repeated the same shape for `:behavior` → `"behavior"` and
18//!    `:upgrade-from` → `"upgradeFrom"`.
19//!
20//! That's the duplication budget violated three ways: same emptiness
21//! check, same camelCase key, same precedence rule, written twice
22//! verbatim. THEORY.md §I.3.5 ("Generation first, composition second,
23//! hand-authoring last; the duplication budget is zero") promotes that
24//! to a build-time concern: every recurring shape lives in a typed
25//! helper before its third occurrence — and PRIME DIRECTIVE work is
26//! exactly that lift.
27//!
28//! [`servico_m2_overlay`] is that helper. Renderers iterate the map it
29//! returns and merge each `(key, value)` pair into their target with
30//! their own map type's `entry().or_insert()` (so `spec.*` precedence
31//! is preserved by construction).
32
33use std::collections::BTreeMap;
34use std::path::{Component, Path, PathBuf};
35use thiserror::Error;
36
37use crate::{Caixa, CaixaKind};
38
39/// Errors the render helpers can raise.
40#[derive(Debug, Error)]
41pub enum RenderError {
42    /// `serde_yaml::to_value` failed for one of the M2 typed slots —
43    /// theoretically impossible for the canonical
44    /// [`crate::LimitsSpec`] / [`crate::BehaviorSpec`] /
45    /// [`crate::UpgradeFromEntry`] types (all derive Serialize without
46    /// fallible custom impls), but surfaced rather than swallowed so a
47    /// future slot whose Serialize impl gains a fallible branch
48    /// surfaces the failure to the caller instead of silently rendering
49    /// as `null` (the prior inline block's behavior).
50    #[error("yaml serialization of M2 slot {slot}: {source}")]
51    Yaml {
52        slot: &'static str,
53        #[source]
54        source: serde_yaml::Error,
55    },
56}
57
58/// Typed kind-mismatch view: the canonical surface every per-kind
59/// `caixa-<target>` renderer raises when it's handed a [`Caixa`] whose
60/// `:kind` doesn't match the kind that renderer is targeting. Carries
61/// the offending caixa's `:nome` alongside the expected/actual kinds,
62/// so the diagnostic reads `caixa "<nome>": expected :kind <expected>,
63/// got <actual>` — naming which caixa needs author attention, not just
64/// which kind the renderer rejected.
65///
66/// Lifted from three identical-shape per-renderer arms in
67/// `caixa-helm` ([`Error::NotAServico`][helm-err]), `caixa-flux`
68/// ([`Error::NotAServico`][flux-err]) and `caixa-mesh`
69/// ([`Error::NotAnAplicacao`][mesh-err]). The prior arms each carried
70/// only the actual [`CaixaKind`], leaving the user to grep for which
71/// `caixa.lisp` triggered the mismatch — exactly the
72/// "feira verb whose error path doesn't name the offending caixa"
73/// punch-list item the compounding-mandate protocol calls out.
74///
75/// Renderers wrap this view in their own [`thiserror`] `Error` enum
76/// via `#[from]`; the `?` operator at every kind-checking call site
77/// turns the [`require_kind`] result into the renderer's local error
78/// type with no manual conversion.
79///
80/// [helm-err]: https://docs.rs/caixa-helm
81/// [flux-err]: https://docs.rs/caixa-flux
82/// [mesh-err]: https://docs.rs/caixa-mesh
83#[derive(Debug, Clone, PartialEq, Eq, Error)]
84#[error("caixa {nome:?}: expected :kind {expected:?}, got {actual:?}")]
85pub struct KindMismatch {
86    /// The offending caixa's `:nome` — names which `caixa.lisp` the
87    /// renderer was handed, so the diagnostic doesn't require the
88    /// user to grep for it.
89    pub nome: String,
90    /// The `:kind` this renderer targets.
91    pub expected: CaixaKind,
92    /// The `:kind` the offending caixa actually carries.
93    pub actual: CaixaKind,
94}
95
96/// Predicate: assert that `caixa.kind == expected`, returning a typed
97/// [`KindMismatch`] view (carrying [`Caixa::nome`]) on rejection. The
98/// canonical entry-point every per-kind renderer wraps in its own
99/// [`thiserror`] `Error` variant via `#[from]` — the call site
100/// becomes a single `caixa_core::require_kind(caixa, CaixaKind::X)?;`
101/// in place of the prior inline `if caixa.kind != CaixaKind::X {
102/// return Err(Error::NotAnX(caixa.kind)); }` block.
103///
104/// Lifted to a single helper so a future per-kind renderer
105/// (`caixa-otel`, the future per-Aplicacao CR materializer the M3.x
106/// roadmap acknowledges, the future per-Supervisor reconciler
107/// renderer) gets the same naming-the-offending-caixa diagnostic for
108/// free, and a future change to the diagnostic format (e.g. adding
109/// a [`Caixa::versao`] suffix once multi-version-skew authoring lands)
110/// is one edit here, not a coordinated rewrite of every renderer.
111///
112/// # Errors
113///
114/// Returns [`KindMismatch`] when `caixa.kind != expected`. The error
115/// carries the caixa's `:nome` so the diagnostic names the offending
116/// `caixa.lisp` — same shape every renderer's `Error::From<KindMismatch>`
117/// converts into the renderer's local error type.
118pub fn require_kind(caixa: &Caixa, expected: CaixaKind) -> Result<(), KindMismatch> {
119    if caixa.kind() == expected {
120        Ok(())
121    } else {
122        Err(KindMismatch {
123            nome: caixa.nome().to_string(),
124            expected,
125            actual: caixa.kind(),
126        })
127    }
128}
129
130/// Typed `:ci`-slot-absence view: the canonical surface every per-`Acao`
131/// consumer raises when it's handed a `:kind Acao` [`Caixa`] whose `:ci`
132/// slot is absent. Carries the offending caixa's `:nome` so the diagnostic
133/// reads `caixa "<nome>": :kind Acao requires a :ci slot` — naming which
134/// `caixa.lisp` needs author attention, not just the axis the consumer
135/// rejected.
136///
137/// Lifted from `caixa-actions`' inline
138/// `.ok_or_else(|| Error::MissingCi { nome: caixa.nome().to_string() })`
139/// gate so a future per-`Acao` consumer (the deferred
140/// `sui-supercacheci::canteiro::emit_gha` workflow renderer, the future
141/// per-`Acao` CR materializer that mirrors the sibling per-`Servico` and
142/// per-`Aplicacao` materializers the M4 roadmap acknowledges) reaches for
143/// the same typed view via `#[from]` instead of re-inlining the same
144/// `.ok_or_else(...)` construction.
145///
146/// Peer of [`KindMismatch`] on the per-renderer kind-gate axis and
147/// [`ServicoCountMismatch`] on the per-Servico V0-count-gate axis — the
148/// third typed named-caixa entry-gate view every per-kind
149/// `caixa-<target>` renderer wraps via `#[from]` in its own
150/// [`thiserror`] `Error` enum.
151#[derive(Debug, Clone, PartialEq, Eq, Error)]
152#[error("caixa {nome:?}: :kind Acao requires a :ci slot")]
153pub struct MissingCiSlot {
154    /// The offending caixa's `:nome` — names which `caixa.lisp` the
155    /// consumer was handed, so the diagnostic doesn't require the user
156    /// to grep for it.
157    pub nome: String,
158}
159
160/// Predicate: assert that `caixa.ci().is_some()`, returning the borrowed
161/// [`canteiro_types::CiRun`] on success and a typed [`MissingCiSlot`] view
162/// (carrying [`Caixa::nome`]) on rejection. The canonical entry-point
163/// every per-`Acao` consumer wraps in its own [`thiserror`] `Error`
164/// variant via `#[from]` — the call site becomes a single
165/// `let ci = caixa_core::require_ci(caixa)?;` in place of the prior
166/// two-line
167/// `let ci = caixa.ci().ok_or_else(|| Error::MissingCi { nome: caixa.nome().to_string() })?;`
168/// block.
169///
170/// Returns `&CiRun` (rather than `()` like the peer [`require_kind`] and
171/// [`require_single_servico`] predicates on the same substrate entry-gate
172/// axis) because every caller then reaches for the borrowed `:ci` slot's
173/// [`canteiro_types::CiRun`] to decompose / render / emit — projecting
174/// the successful borrow through the same `?` step folds the check and
175/// the bind onto one call site, matching how every present + roadmapped
176/// per-`Acao` consumer uses the slot.
177///
178/// Lifted to a single helper so the `:ci`-slot-presence gate — the same
179/// axis the [`crate::LayoutError::MissingCi`] emission gates on at
180/// `feira build` time — lives in exactly one place across every future
181/// per-`Acao` consumer: a future `sui-supercacheci::canteiro::emit_gha`
182/// workflow renderer (the deferred `caixa-actions` next step named in
183/// its own crate docs), a future per-`Acao` CR materializer, and every
184/// consumer downstream reaches for the same typed helper and gets the
185/// same named-the-offending-caixa diagnostic for free.
186///
187/// Same trajectory as [`require_kind`] / [`KindMismatch`] on the peer
188/// per-renderer kind-gate axis and [`require_single_servico`] /
189/// [`ServicoCountMismatch`] on the peer per-Servico V0-count-gate axis:
190/// one `caixa_core::require_*` helper per typed entry-gate axis, so the
191/// diagnostic shape (named caixa, named field) is uniform across the
192/// substrate, and every per-kind renderer's `Error::From<*>` `#[from]`
193/// arm gets the diagnostic-naming-the-offending-caixa contract for free.
194///
195/// # Errors
196///
197/// Returns [`MissingCiSlot`] when `caixa.ci().is_none()` — every
198/// non-`Acao` kind lands here (the sibling
199/// [`crate::LayoutError::CiOnNonAcao`] gate refuses a declared `:ci` on
200/// any other kind at `feira build` time, so a callsite that gates on
201/// `:kind Acao` first via [`require_kind`] will only ever surface this
202/// arm for a `:kind Acao` caixa that hasn't declared its `:ci` yet).
203/// The error carries the caixa's `:nome` so the diagnostic names the
204/// offending `caixa.lisp` — same shape every consumer's
205/// `Error::From<MissingCiSlot>` converts into the consumer's local error
206/// type.
207pub fn require_ci(caixa: &Caixa) -> Result<&canteiro_types::CiRun, MissingCiSlot> {
208    caixa.ci().ok_or_else(|| MissingCiSlot {
209        nome: caixa.nome().to_string(),
210    })
211}
212
213/// Typed `:ci`-decompose-failure view: the canonical surface every
214/// per-`Acao` consumer raises when [`canteiro_types::decompose`] refuses
215/// the caixa's declared `:ci` run (a duplicate node name, a dependency
216/// on an undeclared node, a dependency cycle — every failure mode the
217/// sibling [`canteiro_types::DecomposeError`] enumerates). Carries the
218/// offending caixa's `:nome` alongside the borrowed
219/// [`canteiro_types::DecomposeError`] source so the diagnostic reads
220/// `caixa "<nome>": :ci decompose failed: <source>` — naming which
221/// `caixa.lisp` needs author attention, not just the axis the consumer
222/// rejected.
223///
224/// Lifted from `caixa-actions`' inline `Error::Decompose { nome: String,
225/// #[source] source: DecomposeError }` variant so a future per-`Acao`
226/// consumer (the deferred `sui-supercacheci::canteiro::emit_gha`
227/// workflow renderer named in the `caixa-actions` crate docs, the
228/// future per-`Acao` CR materializer that mirrors the sibling
229/// per-`Servico` / per-`Aplicacao` materializers the M4 roadmap
230/// acknowledges) reaches for the same typed view via `#[from]` instead
231/// of re-inlining the same `nome: String, #[source] source:
232/// DecomposeError` construction on its own call site — the second
233/// typed named-caixa diagnostic axis on the per-`Acao` consumer surface
234/// after the peer [`MissingCiSlot`] presence-gate axis.
235///
236/// Peer of [`MissingCiSlot`] on the per-`Acao` `:ci`-slot diagnostic
237/// axis (the presence gate reaches for [`MissingCiSlot`] via
238/// [`require_ci`]; the decompose gate reaches for [`CiDecomposeFailure`]
239/// on the borrowed [`canteiro_types::CiRun`] the presence gate returns).
240/// Peer of [`KindMismatch`] / [`ServicoCountMismatch`] on the sibling
241/// per-renderer entry-gate diagnostic axes — extends the same "one
242/// typed view per axis, carrying the offending caixa's `:nome` +
243/// axis-specific detail, wrapped by every consumer via `#[from]`"
244/// discipline onto the [`canteiro_types::decompose`] axis on the
245/// per-`Acao` consumer surface.
246///
247/// The `source` field carries the borrowed
248/// [`canteiro_types::DecomposeError`] verbatim (rather than collapsing
249/// to a single opaque axis) so a future consumer that wants to fan on
250/// the specific decompose-failure arm — a `feira lint` sub-diagnostic
251/// that offers a `:deps`-repair suggestion on the `MissingDependency`
252/// arm but not the `Cycle` arm, a future per-`Acao` CR materializer's
253/// admission webhook that surfaces the cycle path on rejection —
254/// reaches for `err.source` directly rather than re-parsing the Display
255/// bytes.
256///
257/// [`DecomposeError`]: canteiro_types::DecomposeError
258#[derive(Debug, Error)]
259#[error("caixa {nome:?}: :ci decompose failed: {source}")]
260pub struct CiDecomposeFailure {
261    /// The offending caixa's `:nome` — names which `caixa.lisp` the
262    /// consumer was handed, so the diagnostic doesn't require the user
263    /// to grep for it. Constructed via the lifted [`crate::Caixa::nome`]
264    /// accessor's `.to_string()` extension, matching the peer
265    /// [`MissingCiSlot::nome`] / [`KindMismatch::nome`] /
266    /// [`ServicoCountMismatch::nome`] `nome`-carrying axes.
267    pub nome: String,
268    /// The [`canteiro_types::decompose`] error the caixa's `:ci` run
269    /// tripped on — carried verbatim so a consumer that fans on the
270    /// specific arm (`Cycle` / `MissingDependency` / `DuplicateNode` /
271    /// …) reaches for the typed source rather than re-parsing the
272    /// Display bytes.
273    #[source]
274    pub source: canteiro_types::DecomposeError,
275}
276
277/// Predicate: decompose a borrowed [`canteiro_types::CiRun`] into its
278/// typed [`canteiro_types::CanteiroDag`] via
279/// [`canteiro_types::decompose`], wrapping any
280/// [`canteiro_types::DecomposeError`] in a typed [`CiDecomposeFailure`]
281/// view (carrying [`Caixa::nome`]) on rejection. The canonical
282/// entry-point every per-`Acao` consumer wraps in its own
283/// [`thiserror`] `Error` variant via `#[from]` — the call site becomes
284/// a single `let cd = caixa_core::decompose_ci(caixa, ci)?;` in place
285/// of the prior inline
286/// `let cd = canteiro_types::decompose(ci).map_err(|source| CiDecomposeFailure { nome: caixa.nome().to_string(), source })?;`
287/// block.
288///
289/// Takes the borrowed [`canteiro_types::CiRun`] as a separate argument
290/// (rather than re-borrowing it through [`require_ci`] internally) so
291/// the axis stays single-purpose — the sibling [`require_ci`] presence
292/// gate returns the borrowed slot, this predicate consumes it, and the
293/// two together form the substrate-canonical two-line per-`Acao` prelude
294/// `let ci = caixa_core::require_ci(caixa)?; let cd = caixa_core::decompose_ci(caixa, ci)?;`
295/// every present + roadmapped per-`Acao` consumer runs at its
296/// entry-point (matching how the sibling per-Servico entry-gate axes
297/// keep [`require_kind`] and [`require_single_servico`] as separate
298/// primitives, then compose them into the V0-shape
299/// [`require_v0_servico_shape`] helper — the compound `require + decompose`
300/// helper is a peer-lift for a later commit when a second per-`Acao`
301/// consumer arrives). The `caixa: &Caixa` argument is what makes the
302/// diagnostic name the offending `caixa.lisp` — the borrowed
303/// [`Caixa::nome`] accessor projects through the typed-view
304/// constructor unchanged, matching the peer [`require_ci`] /
305/// [`require_kind`] / [`require_single_servico`] typed-view constructors.
306///
307/// Lifted to a single helper so the [`canteiro_types::decompose`]
308/// axis — the same axis every per-`Acao` consumer runs on its declared
309/// `:ci` slot — lives in exactly one place across every future
310/// per-`Acao` consumer: a future `sui-supercacheci::canteiro::emit_gha`
311/// workflow renderer (the deferred `caixa-actions` next step named in
312/// its own crate docs), a future per-`Acao` CR materializer's admission
313/// webhook, a future `feira lint` sub-diagnostic that offers a
314/// `:deps`-repair suggestion on the [`canteiro_types::DecomposeError::MissingDependency`]
315/// arm but not the [`canteiro_types::DecomposeError::Cycle`] arm — every
316/// consumer reaches for the same one-liner + `#[from]` and gets the
317/// diagnostic-naming-the-offending-caixa contract for free.
318///
319/// Same trajectory as [`require_kind`] / [`KindMismatch`] on the peer
320/// per-renderer kind-gate axis, [`require_single_servico`] /
321/// [`ServicoCountMismatch`] on the peer per-Servico V0-count-gate
322/// axis, and [`require_ci`] / [`MissingCiSlot`] on the peer per-`Acao`
323/// presence-gate axis: one `caixa_core::require_*`/`decompose_ci`
324/// helper per typed axis, so the diagnostic shape (named caixa, named
325/// field) is uniform across the substrate, and every consumer's
326/// `Error::From<*>` `#[from]` arm gets the diagnostic-naming-the-
327/// offending-caixa contract for free.
328///
329/// # Errors
330///
331/// Returns [`CiDecomposeFailure`] when [`canteiro_types::decompose`]
332/// refuses the borrowed `:ci` run — every failure mode the sibling
333/// [`canteiro_types::DecomposeError`] enumerates (a duplicate node
334/// name, a dependency on an undeclared node, a dependency cycle) lands
335/// on this arm. The error carries the caixa's `:nome` + the underlying
336/// [`canteiro_types::DecomposeError`] verbatim so the diagnostic names
337/// the offending `caixa.lisp` and a consumer that fans on the specific
338/// arm reaches for `err.source` directly rather than re-parsing the
339/// Display bytes — same shape every consumer's
340/// `Error::From<CiDecomposeFailure>` converts into the consumer's local
341/// error type.
342pub fn decompose_ci(
343    caixa: &Caixa,
344    ci: &canteiro_types::CiRun,
345) -> Result<canteiro_types::CanteiroDag, CiDecomposeFailure> {
346    canteiro_types::decompose(ci).map_err(|source| CiDecomposeFailure {
347        nome: caixa.nome().to_string(),
348        source,
349    })
350}
351
352/// Substrate-canonical per-`Acao` declared-edge-count projection every
353/// consumer of a borrowed [`canteiro_types::CiRun`] that needs the total
354/// number of author-declared `deps` edges across every
355/// [`canteiro_types::CiNode`] keys off — returns the plain [`usize`] sum
356/// `ci.nodes.iter().map(|n| n.deps.len()).sum()` verbatim, without
357/// running [`canteiro_types::decompose`] again (the count is a property
358/// of the borrowed run's shape, not of the owned
359/// [`canteiro_types::CanteiroDag`] the sibling [`decompose_ci`] returns
360/// — an author-declared cycle carries the same edge count as an
361/// author-declared linear DAG of the same node-and-dep list).
362///
363/// The declared-edge-count axis carries the "how many `deps` edges did
364/// this repo's CI author write?" projection every per-`Acao` consumer
365/// downstream fans on: the `caixa_actions::RenderedAcao::edge_count`
366/// artifact the M0 renderer's `validate` returns (paired with the
367/// topological node-name list from `cd.topo_order()`), the deferred
368/// `sui-supercacheci::canteiro::emit_gha` workflow renderer's
369/// per-workflow `jobs.<job>.needs` count reconciliation pass (each
370/// `needs` entry maps 1:1 to a `deps` edge, so a renderer that emits N
371/// edges must have consumed exactly `declared_edge_count` `needs`
372/// entries across the fan-out), a future `feira lint --acao` per-caixa
373/// admission verb's per-repo declared-edge summary, a future M4
374/// `acao.pleme.io/v1alpha1/Acao` CR materializer's admission webhook
375/// spanning the declared edge count against a per-tenant complexity cap.
376///
377/// Prior to this lift the `ci.nodes.iter().map(|n| n.deps.len()).sum()`
378/// expression was inlined at two sites — `caixa_actions::validate`'s
379/// `edge_count` field construction at `caixa-actions/src/lib.rs:159`
380/// (the M0 per-`Acao` renderer's sole production consumer) and its own
381/// [`require_acao_view`] byte-parity pin at `caixa-actions/src/lib.rs:735`
382/// (which reconstructs the same sum through the compound helper's
383/// returned `&CiRun` to pin that the two paths agree) — two open-coded
384/// arithmetic expressions that expressed no compile-time link back to
385/// the typed [`canteiro_types::CiRun`] axis, so a future refactor of
386/// the declared-edge-count shape (a promotion of the plain [`usize`]
387/// sum to a `{intra_workspace, cross_workspace}` split once
388/// [`canteiro_types::CiNode`] grows a workspace-scoped edge kind, a
389/// per-`:ci` `deps`-edge-canonicalization pass that collapses duplicate
390/// edges once the canteiro-types axis grows a set-shaped `deps`
391/// representation, a per-env-class edge-weight overlay once the M4
392/// `EnvClass` axis grows a per-edge cost model) would have had to be
393/// threaded through both open-coded copies in lockstep or the M0
394/// renderer's `edge_count` artifact would silently disagree with its
395/// own byte-parity pin. Lifting the projection to a typed method on the
396/// substrate primitive means every downstream consumer of the `Acao`'s
397/// declared-edge-count surface reaches for exactly one typed
398/// dispatch — the resolver's accept-set migrates as a unit on any
399/// future axis addition.
400///
401/// The docstring on [`require_acao_view`] already named this expression
402/// verbatim ("the borrowed run for per-[`canteiro_types::CiNode`] axes
403/// (`ci.nodes.iter().map(|n| n.deps.len()).sum()` for the declared edge
404/// count …)") but the substrate carried no primitive for it — the
405/// citation was documentation-only, and the two open-coded call sites
406/// re-expressed the arithmetic each time. This lift closes that gap:
407/// the docstring now cites the substrate primitive by name and every
408/// consumer reaches for the same [`ci_declared_edge_count`] one-liner.
409///
410/// Peer of the sibling [`require_ci`] / [`decompose_ci`] /
411/// [`require_acao_view`] per-`Acao` primitives on the substrate's
412/// per-kind renderer entry-gate surface, extended onto the "borrowed
413/// [`canteiro_types::CiRun`] scalar projection" axis (the two prior
414/// primitives return borrowed / owned structural artifacts; this one
415/// returns a plain [`usize`] scalar over the borrowed run's node-list
416/// shape). Same "one typed dispatch on the substrate primitive, thin
417/// projections at each consumer" discipline the peer per-`Aplicacao`
418/// [`crate::aplicacao::AplicacaoSpec::port_for_destination`] scalar
419/// projection carries on the per-Aplicacao `:entrada` port-resolution
420/// axis, extended onto the per-`Acao` `:ci` declared-edge-count axis.
421///
422/// Named `ci_declared_edge_count` (rather than `declared_edge_count`)
423/// to keep the substrate-side helper namespace explicit that the input
424/// axis is a `:ci` slot — matching the peer [`require_ci`] /
425/// [`decompose_ci`] `ci_`-prefix-shaped naming convention the sibling
426/// per-`Acao` substrate primitives already carry, so a caller reading
427/// `caixa_core::ci_declared_edge_count(ci)` sees the axis at the
428/// helper name rather than at a lifted-out `use` alias.
429#[must_use]
430pub fn ci_declared_edge_count(ci: &canteiro_types::CiRun) -> usize {
431    ci.nodes.iter().map(|n| n.deps.len()).sum()
432}
433
434/// Typed `:servicos`-count-mismatch view: the canonical surface every
435/// per-Servico `caixa-<target>` renderer raises when it's handed a
436/// [`Caixa`] whose `:servicos` list doesn't carry exactly one entry —
437/// the V0 contract every Servico-kind caixa satisfies (`caixa-helm`'s
438/// `render_chart_for_servico`, `caixa-flux`'s `programs_yaml_entry`, the
439/// future per-Servico OCI/wasm packager). Carries the offending caixa's
440/// `:nome` alongside the actual count, so the diagnostic reads `caixa
441/// "<nome>": :servicos must declare exactly one entry for V0 (got
442/// <count>)` — naming which `caixa.lisp` needs author attention, not
443/// just the count the renderer rejected.
444///
445/// Lifted from two identical-shape per-renderer arms in
446/// [`caixa-helm`][helm-err] and [`caixa-flux`][flux-err]
447/// (`Error::UnsupportedServicoCount(usize)`). The prior arms each
448/// carried only the actual count, leaving the user to grep for which
449/// `caixa.lisp` triggered the mismatch — exactly the "feira verb whose
450/// error path doesn't name the offending caixa" punch-list item the
451/// compounding-mandate protocol calls out. Same trajectory as
452/// [`KindMismatch`] (which lifted the prior `NotAServico(CaixaKind)` /
453/// `NotAnAplicacao(CaixaKind)` per-renderer arms into a typed view
454/// naming the offending caixa).
455///
456/// Renderers wrap this view in their own [`thiserror`] `Error` enum
457/// via `#[from]`; the `?` operator at every count-checking call site
458/// turns the [`require_single_servico`] result into the renderer's
459/// local error type with no manual conversion. Peer to [`require_kind`]
460/// on the V0 Servico-shape gate axis (the kind gate refuses the wrong
461/// `:kind`; this gate refuses the wrong `:servicos` count) — every
462/// per-Servico renderer chains both at its entry point.
463///
464/// [helm-err]: https://docs.rs/caixa-helm
465/// [flux-err]: https://docs.rs/caixa-flux
466#[derive(Debug, Clone, PartialEq, Eq, Error)]
467#[error("caixa {nome:?}: :servicos must declare exactly one entry for V0 (got {count})")]
468pub struct ServicoCountMismatch {
469    /// The offending caixa's `:nome` — names which `caixa.lisp` the
470    /// renderer was handed, so the diagnostic doesn't require the
471    /// user to grep for it.
472    pub nome: String,
473    /// The `:servicos` list length the offending caixa actually carries.
474    /// The expected count is fixed at 1 by the V0 contract — every
475    /// `:kind Servico` caixa declares exactly one `ComputeUnit` YAML
476    /// pointer, matching the one Helm chart / one programs.yaml entry
477    /// each renderer emits.
478    pub count: usize,
479}
480
481/// Predicate: assert that `caixa.servicos.len() == 1`, returning a typed
482/// [`ServicoCountMismatch`] view (carrying [`Caixa::nome`] + the actual
483/// count) on rejection. The canonical entry-point every per-Servico
484/// renderer wraps in its own [`thiserror`] `Error` variant via
485/// `#[from]` — the call site becomes a single
486/// `caixa_core::require_single_servico(caixa)?;` in place of the prior
487/// inline `if caixa.servicos.len() != 1 { return
488/// Err(Error::UnsupportedServicoCount(caixa.servicos.len())); }`
489/// block.
490///
491/// Lifted to a single helper so the V0 `:servicos`-singularity invariant
492/// — the same shape the [`crate::Caixa::validate_code_paths`] doc
493/// comment already names as load-bearing on caixa-helm + caixa-flux
494/// (caixa-core/src/manifest.rs:4108) — lives in exactly one place across
495/// every per-Servico renderer. A future per-Servico renderer
496/// (`caixa-otel`, the future per-Servico OCI packager, the future M4
497/// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer) gets the same
498/// naming-the-offending-caixa diagnostic for free, and a future change
499/// to the V0 invariant (e.g. allowing multi-servico Servicos when the
500/// component-model multi-world boundary lands in M5) is one edit here,
501/// not a coordinated rewrite of every renderer's per-arm
502/// `UnsupportedServicoCount` check.
503///
504/// Same trajectory as [`require_kind`] / [`KindMismatch`] on the peer
505/// V0 Servico-shape axis: every per-Servico renderer reaches for one
506/// `caixa_core::require_*` helper per V0 invariant, so the diagnostic
507/// shape (named caixa, named field) is uniform across the substrate.
508///
509/// # Errors
510///
511/// Returns [`ServicoCountMismatch`] when `caixa.servicos.len() != 1`
512/// (both empty and ≥ 2 land on this arm — the V0 contract requires
513/// *exactly* one entry, not *at-least* one). The error carries the
514/// caixa's `:nome` + the offending count so the diagnostic names the
515/// offending `caixa.lisp` — same shape every renderer's
516/// `Error::From<ServicoCountMismatch>` converts into the renderer's
517/// local error type.
518pub fn require_single_servico(caixa: &Caixa) -> Result<(), ServicoCountMismatch> {
519    if caixa.servicos().len() == 1 {
520        Ok(())
521    } else {
522        Err(ServicoCountMismatch {
523            nome: caixa.nome().to_string(),
524            count: caixa.servicos().len(),
525        })
526    }
527}
528
529/// Compound V0-shape entry gate: the canonical two-line
530/// `require_kind(caixa, Servico)? + require_single_servico(caixa)?`
531/// prelude every per-Servico `caixa-<target>` renderer runs at its
532/// entry-point, collapsed onto one call the caller reads as intent
533/// ("gate the input on the V0 Servico shape") rather than two
534/// hand-spelled predicate calls.
535///
536/// The pair names one contract with two axes: `:kind` is `Servico`
537/// (this is a per-Servico renderer's input, not a `Biblioteca` /
538/// `Binario` / `Supervisor` / `Aplicacao` mis-hand-off) *and*
539/// `:servicos.len() == 1` (the V0 contract every Servico caixa
540/// satisfies — one `ComputeUnit` YAML pointer, matching the one Helm
541/// chart / programs.yaml entry / cluster bundle each per-Servico
542/// renderer emits). Both axes must hold together — a `:kind Servico`
543/// caixa with two `:servicos` entries and a `:kind Aplicacao` caixa
544/// with one `:servicos` entry are equally invalid at every per-Servico
545/// renderer's entry-point — so lifting the pair onto one helper names
546/// the compound contract at each call site the way the M2 typed slots'
547/// [`servico_m2_overlay`] names the compound `:limits`+`:behavior`+
548/// `:upgrade-from` overlay contract at each call site.
549///
550/// Three production call sites previously carried the two-line pair
551/// inline:
552///
553///   * `caixa-flux`'s [`programs_yaml_entry`][flux-yaml] (the
554///     aggregator-path programs.yaml entry emitter);
555///   * `caixa-flux`'s [`cluster_bundle`][flux-bundle] (the standalone
556///     `GitRepository` + `HelmRelease` + `Kustomization` trio emitter);
557///   * `caixa-helm`'s
558///     [`render_chart_for_servico_with`][helm-chart] (the per-program
559///     `lareira-<nome>` Helm chart emitter).
560///
561/// Each site now reads `caixa_core::require_v0_servico_shape(caixa)?`
562/// instead of the two-line pair. A future per-Servico renderer
563/// (`caixa-otel`, the future per-Servico OCI packager, the future M4
564/// `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer,
565/// MESH-COMPOSITION §III.2 #5) gets the compound V0-shape gate for
566/// free with one call, instead of re-inlining the two-line pair — and
567/// a future change to the V0 contract (e.g. adding a
568/// `:kind Servico`-only `:computeunits`-slot-shape gate when the
569/// component-model multi-world boundary lands in M5) is one edit here,
570/// not a coordinated rewrite of every renderer's inline pair.
571///
572/// The generic error type `E` accepts every renderer's local
573/// [`thiserror`] `Error` enum that carries both [`KindMismatch`] and
574/// [`ServicoCountMismatch`] via `#[from]` (`caixa_flux::Error`,
575/// `caixa_helm::Error`, and every future per-Servico renderer that
576/// wires both `#[from]` arms as the diagnostic-naming-the-offending-
577/// caixa contract already requires). Type inference at the call site
578/// resolves `E` from the caller's `?` return type, so the call reads
579/// as `caixa_core::require_v0_servico_shape(caixa)?` with no explicit
580/// turbofish — the same one-liner shape every peer `require_kind` /
581/// `require_single_servico` call site already reads as.
582///
583/// Peer to [`require_kind`] on the single-axis kind gate and
584/// [`require_single_servico`] on the single-axis count gate — both
585/// primitives stay public because per-non-Servico renderers
586/// (`caixa-mesh`'s per-Aplicacao gate, `caixa-feira`'s
587/// `first_servico_path` per-verb gate that composes both predicates
588/// with `anyhow::Context`) reach for the individual predicates rather
589/// than the compound one. Peer to [`servico_m2_overlay`] on the
590/// sibling per-Servico compound-contract surface: `servico_m2_overlay`
591/// names the compound M2 emit-side contract, `require_v0_servico_shape`
592/// names the compound V0 gate-side contract, both per-Servico shape.
593///
594/// [flux-yaml]: https://docs.rs/caixa-flux
595/// [flux-bundle]: https://docs.rs/caixa-flux
596/// [helm-chart]: https://docs.rs/caixa-helm
597///
598/// # Errors
599///
600/// Returns the caller's `E` wrapping a [`KindMismatch`] when
601/// `caixa.kind != CaixaKind::Servico`, or a [`ServicoCountMismatch`]
602/// when `caixa.servicos.len() != 1`. Order matches the two-line pair
603/// this replaces: the kind gate fires first, so a
604/// `:kind Aplicacao` caixa with zero `:servicos` entries surfaces the
605/// kind mismatch (the more actionable diagnostic — the author has the
606/// wrong `:kind`) rather than the count mismatch (a downstream
607/// consequence of the mis-kinded input).
608pub fn require_v0_servico_shape<E>(caixa: &Caixa) -> Result<(), E>
609where
610    E: From<KindMismatch> + From<ServicoCountMismatch>,
611{
612    require_kind(caixa, CaixaKind::Servico)?;
613    require_single_servico(caixa)?;
614    Ok(())
615}
616
617/// Compound per-Aplicacao entry gate: the canonical three-line
618/// `require_kind(caixa, CaixaKind::Aplicacao)? +
619/// caixa.aplicacao_view().expect(…) + spec.validate()?` prelude every
620/// per-Aplicacao `caixa-<target>` renderer runs at its entry-point,
621/// collapsed onto one call the caller reads as intent ("gate the input
622/// on the V0 Aplicacao shape and hand back a validated
623/// [`crate::aplicacao::AplicacaoSpec`]") rather than three hand-spelled
624/// steps.
625///
626/// The cascade names one contract with three axes: `:kind` is
627/// `Aplicacao` (this is a per-Aplicacao renderer's input, not a
628/// `Biblioteca` / `Binario` / `Servico` / `Supervisor` / `Acao`
629/// mis-hand-off), the [`Caixa::aplicacao_view`] fold-in succeeds (which
630/// [`require_kind`]-on-`Aplicacao` guarantees per its own doc pin —
631/// [`Caixa::aplicacao_view`] returns `Some` iff `caixa.kind().is_aplicacao()`),
632/// *and* the folded [`crate::aplicacao::AplicacaoSpec`] passes its own
633/// M3 typed-shape validation ([`crate::aplicacao::AplicacaoSpec::validate`]:
634/// non-empty `:membros`, DNS-1123 member names, semver-valid `:versao`
635/// requirements, `:contratos` referencing only declared members,
636/// `:placement Sharded` carrying `:shard-key`, `:placement`
637/// `Replicated`/`SingleNode` carrying `:clusters`, and so on across
638/// every M3 typed slot). All three axes must hold together — a
639/// `:kind Servico` caixa carrying a well-formed `:membros`/`:contratos`
640/// stanza (the manifest field's documented "silently ignored" case)
641/// and a `:kind Aplicacao` caixa with an empty `:membros` are equally
642/// invalid at every per-Aplicacao renderer's entry-point — so lifting
643/// the three-arm cascade onto one helper names the compound contract
644/// at each call site the way the sibling per-Servico
645/// [`require_v0_servico_shape`] compound gate already names the
646/// two-axis compound V0 Servico-shape contract.
647///
648/// Three production call sites in `caixa-mesh` previously funneled
649/// through the crate-local `typed_view` wrapper which itself carried
650/// the three-line cascade inline:
651///
652///   * `caixa-mesh`'s [`programs_for_aplicacao`][mesh-programs] (the
653///     `lareira-fleet-programs`-aggregator programs.yaml fan-out
654///     emitter);
655///   * `caixa-mesh`'s [`cilium_network_policies`][mesh-cnp] (the
656///     per-`(:de, :para)` L7 Cilium CRD emitter);
657///   * `caixa-mesh`'s [`gateway_routes`][mesh-gw] (the per-`:entrada`
658///     K8s Gateway API v1 Gateway + HTTPRoute emitter).
659///
660/// The crate-local `caixa_mesh::typed_view` wrapper now reads as a
661/// one-liner `caixa_core::require_aplicacao_view::<Error>(caixa)`. A
662/// future per-Aplicacao renderer (`caixa-tatara`'s per-Aplicacao
663/// [`process_for_aplicacao`][tatara] downstream axes when they grow a
664/// spec-consuming validate arm, the deferred
665/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission
666/// webhook, a future `feira validate --aplicacao` per-caixa admission
667/// verb) gets the compound three-arm gate for free with one call,
668/// instead of re-inlining the three-line cascade — and a future change
669/// to the V0 Aplicacao contract (e.g. adding a `:kind Aplicacao`-only
670/// `:membros`-cross-cluster-uniqueness gate when the M4 federated-app
671/// boundary lands) is one edit here, not a coordinated rewrite of
672/// every per-Aplicacao renderer's inline cascade.
673///
674/// The generic error type `E` accepts every per-Aplicacao renderer's
675/// local [`thiserror`] `Error` enum that carries both [`KindMismatch`]
676/// and [`crate::aplicacao::AplicacaoError`] via `#[from]`
677/// (`caixa_mesh::Error`, and every future per-Aplicacao renderer that
678/// wires both `#[from]` arms as the diagnostic-naming-the-offending-
679/// caixa contract already requires). Type inference at the call site
680/// resolves `E` from the caller's `?` return type, though a caller
681/// that assigns the result directly to a `Result<AplicacaoSpec,
682/// Error>` binding may need a turbofish
683/// (`::<Error>`) — matching the sibling `require_v0_servico_shape::<Error>`
684/// turbofish convention the peer per-Servico call sites already read.
685///
686/// Peer to [`require_v0_servico_shape`] on the sibling per-Servico
687/// entry-gate axis and [`require_kind`] / [`require_ci`] /
688/// [`decompose_ci`] on the sibling per-`Acao` entry-gate axis — every
689/// per-kind renderer's entry-gate cascade now lives in exactly one
690/// substrate primitive.
691///
692/// [mesh-programs]: https://docs.rs/caixa-mesh
693/// [mesh-cnp]: https://docs.rs/caixa-mesh
694/// [mesh-gw]: https://docs.rs/caixa-mesh
695/// [tatara]: https://docs.rs/caixa-tatara
696///
697/// # Errors
698///
699/// Returns the caller's `E` wrapping a [`KindMismatch`] when
700/// `caixa.kind != CaixaKind::Aplicacao`, or a
701/// [`crate::aplicacao::AplicacaoError`] when the folded
702/// [`crate::aplicacao::AplicacaoSpec`] fails its typed-shape
703/// validation. Order matches the three-line cascade this replaces: the
704/// kind gate fires first, so a `:kind Servico` caixa with a
705/// well-formed `:membros` stanza surfaces the kind mismatch (the more
706/// actionable diagnostic — the author has the wrong `:kind`) rather
707/// than the `AplicacaoError` (which the [`Caixa::aplicacao_view`]
708/// fold-in never even reaches on a non-`Aplicacao` kind).
709///
710/// # Panics
711///
712/// Never in practice — the internal [`Caixa::aplicacao_view`] unwrap
713/// is guarded by the preceding [`require_kind`]-on-`Aplicacao` gate,
714/// and [`Caixa::aplicacao_view`]'s own doc pin guarantees
715/// `Some`-return iff `caixa.kind().is_aplicacao()`. A future
716/// [`Caixa::aplicacao_view`] refactor that decouples `Some`-return
717/// from `caixa.kind().is_aplicacao()` would trip this panic at the
718/// first per-Aplicacao renderer call site, not silently return `Err(E)`
719/// at every one — the panic message names the substrate invariant so
720/// the offending edit is obvious.
721pub fn require_aplicacao_view<E>(caixa: &Caixa) -> Result<crate::aplicacao::AplicacaoSpec, E>
722where
723    E: From<KindMismatch> + From<crate::aplicacao::AplicacaoError>,
724{
725    require_kind(caixa, CaixaKind::Aplicacao)?;
726    let spec = caixa
727        .aplicacao_view()
728        .expect("require_kind(Aplicacao) guarantees Caixa::aplicacao_view returns Some");
729    spec.validate()?;
730    Ok(spec)
731}
732
733/// Compound per-`Acao` entry gate: the canonical three-line
734/// `require_kind(caixa, CaixaKind::Acao)? + require_ci(caixa)? +
735/// decompose_ci(caixa, ci)?` prelude every per-`Acao` `caixa-<target>`
736/// consumer runs at its entry-point, collapsed onto one call the caller
737/// reads as intent ("gate the input on the V0 Acao shape and hand back
738/// the borrowed [`canteiro_types::CiRun`] + the decomposed
739/// [`canteiro_types::CanteiroDag`]") rather than three hand-spelled
740/// steps.
741///
742/// The cascade names one contract with three axes: `:kind` is `Acao`
743/// (this is a per-`Acao` consumer's input, not a `Biblioteca` /
744/// `Binario` / `Servico` / `Supervisor` / `Aplicacao` mis-hand-off),
745/// the `:ci` slot is present ([`require_ci`] returns the borrowed
746/// [`canteiro_types::CiRun`]), *and* the declared run decomposes
747/// cleanly through [`canteiro_types::decompose`] (a duplicate node
748/// name, a missing dep, a cycle — every [`canteiro_types::DecomposeError`]
749/// arm — surfaces via [`CiDecomposeFailure`]). All three axes must
750/// hold together — so lifting the three-arm cascade onto one helper
751/// names the compound contract at each call site the way the sibling
752/// per-Servico [`require_v0_servico_shape`] compound gate already
753/// names the two-axis compound V0 Servico-shape contract and the
754/// sibling per-Aplicacao [`require_aplicacao_view`] compound gate
755/// names the three-arm compound per-Aplicacao entry-gate contract.
756///
757/// Returns the borrowed [`canteiro_types::CiRun`] paired with the
758/// owned [`canteiro_types::CanteiroDag`] `decompose_ci` produced —
759/// both are the load-bearing artifacts every per-`Acao` consumer
760/// reads past the gate: the borrowed run for
761/// per-[`canteiro_types::CiNode`] axes (the substrate primitive
762/// [`ci_declared_edge_count`] for the declared edge count, the
763/// deferred `sui-supercacheci::canteiro::emit_gha` per-node YAML emit
764/// surface), the owned DAG for topological order (`cd.topo_order()`,
765/// which the substrate's own [`decompose_ci`] pass-through-on-success
766/// contract at [`decompose_ci_accepts_valid_ci_run_and_returns_canteiro_dag`]
767/// pins as infallible on the accepted arm).
768///
769/// The current single production call site — `caixa-actions::validate` —
770/// previously carried the three-line prelude inline:
771///
772/// ```ignore
773/// caixa_core::require_kind(caixa, CaixaKind::Acao)?;
774/// let ci = caixa_core::require_ci(caixa)?;
775/// let cd = caixa_core::decompose_ci(caixa, ci)?;
776/// ```
777///
778/// It now reads as a one-liner
779/// `let (ci, cd) = caixa_core::require_acao_view::<Error>(caixa)?;`.
780/// Every deferred per-`Acao` consumer named in the `caixa-actions` crate
781/// docs (the `sui-supercacheci::canteiro::emit_gha` workflow renderer, a
782/// future `acao.pleme.io/v1alpha1/Acao` CR materializer's admission
783/// webhook, a future `feira validate --acao` per-caixa admission verb)
784/// gets the compound three-arm gate for free with one call, instead of
785/// re-inlining the three-line prelude — and a future change to the V0
786/// Acao contract (an M4 [`canteiro_types::CiRun`] `:workspace`-scoped
787/// admission gate the CR materializer resolves at admission time, a
788/// per-`:ci` cross-node capability-audit prelude the Pony-inspired
789/// capability-typing roadmap acknowledges) is one edit here on the
790/// compound helper, not a coordinated rewrite across every per-`Acao`
791/// consumer's inline three-line prelude.
792///
793/// The generic error type `E` accepts every per-`Acao` consumer's
794/// local [`thiserror`] `Error` enum that carries all three of
795/// [`KindMismatch`], [`MissingCiSlot`], and [`CiDecomposeFailure`]
796/// via `#[from]` (`caixa_actions::Error` today, and every future
797/// per-`Acao` consumer that wires the same three `#[from]` arms as
798/// the diagnostic-naming-the-offending-caixa contract already
799/// requires). Type inference at the call site resolves `E` from the
800/// caller's `?` return type, though a caller that assigns the result
801/// directly to a `Result<(&CiRun, CanteiroDag), Error>` binding may
802/// need a turbofish (`::<Error>`) — matching the sibling
803/// `require_aplicacao_view::<Error>` turbofish convention the peer
804/// per-Aplicacao call site already reads.
805///
806/// Peer to [`require_v0_servico_shape`] on the sibling per-Servico
807/// entry-gate axis and [`require_aplicacao_view`] on the sibling
808/// per-Aplicacao entry-gate axis — every per-kind renderer's
809/// entry-gate cascade now lives in exactly one substrate primitive.
810///
811/// # Errors
812///
813/// Returns the caller's `E` wrapping a [`KindMismatch`] when
814/// `caixa.kind != CaixaKind::Acao`, a [`MissingCiSlot`] when the
815/// caixa's `:ci` slot is absent past the kind gate, or a
816/// [`CiDecomposeFailure`] when [`canteiro_types::decompose`] refuses
817/// the borrowed run. Order matches the three-line prelude this
818/// replaces: the kind gate fires first (so a `:kind Servico` caixa
819/// carrying a well-formed `:ci` stanza — the manifest field's
820/// documented "silently ignored" case on a non-`Acao` kind —
821/// surfaces the kind mismatch, the more actionable diagnostic), then
822/// the presence gate, then the decompose gate.
823pub fn require_acao_view<E>(
824    caixa: &Caixa,
825) -> Result<(&canteiro_types::CiRun, canteiro_types::CanteiroDag), E>
826where
827    E: From<KindMismatch> + From<MissingCiSlot> + From<CiDecomposeFailure>,
828{
829    require_kind(caixa, CaixaKind::Acao)?;
830    let ci = require_ci(caixa)?;
831    let cd = decompose_ci(caixa, ci)?;
832    Ok((ci, cd))
833}
834
835/// One rendered artifact — a `(path, contents)` pair every per-target
836/// `caixa-<target>` renderer emits at every leaf of its output tree.
837/// Carries the sandboxed relative path the substrate writes the artifact
838/// under (relative to the renderer-chosen output root — the per-chart
839/// directory for [`caixa-helm`][cf-helm]'s `lareira-<nome>` chart tree,
840/// the per-caixa `./clusters/<cluster>/services/<nome>/` sub-tree for
841/// [`caixa-flux`][cf-flux]'s [`cluster_bundle`][cb] Flux v2 CR trio)
842/// alongside the pre-serialized byte contents the substrate writes to it.
843///
844/// Lifted from two identical-shape per-renderer arms in
845/// [`caixa-flux`][cf-flux] (`BundleFile { path: PathBuf, contents:
846/// String }`) and [`caixa-helm`][cf-helm] (`ChartFile { path: PathBuf,
847/// contents: String }`) — same field pair, same derives (`Debug + Clone
848/// + PartialEq + Eq`), no per-type impls — carrying the same "one
849/// rendered leaf artifact" contract twice. Every prior per-target
850/// renderer had reinvented the same two-field record because there was
851/// no substrate-side canonical `(path, contents)` shape to reach for;
852/// the future per-target renderers the M4/M5 roadmap acknowledges
853/// (`caixa-otel`'s per-collector-config emit, the future per-Aplicacao
854/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-CR YAML
855/// emit, the future per-Supervisor reconciler renderer's per-child
856/// bundle emit) would have re-added a third and fourth clone of the
857/// same record — exactly the "render-side patterns recurring ≥2 times
858/// across `caixa-helm` / `caixa-flux` / `caixa-mesh` become helpers.
859/// Duplication is a bug. (PRIME DIRECTIVE.)" compounding-mandate slot
860/// item.
861///
862/// Both prior arms remain as public `pub type BundleFile =
863/// caixa_core::RenderedFile;` / `pub type ChartFile =
864/// caixa_core::RenderedFile;` aliases at their crate boundary so every
865/// existing struct-literal construction site
866/// (`BundleFile { path: …, contents: … }` / `ChartFile { path: …,
867/// contents: … }`), every field-access site (`.path` / `.contents`),
868/// and every derive-fed navigator (`==` equality pins, `Debug`
869/// formatting probes) resolves through the type alias to the canonical
870/// [`RenderedFile`] with no per-call-site edit — Rust type aliases
871/// carry the same `#[derive]`-generated `Debug`/`Clone`/`PartialEq`/
872/// `Eq` impls as their canonical, so the shared-shape contract lives
873/// at one type definition instead of two verbatim clones drifting
874/// silently on any future rebrand.
875///
876/// Peer to the [`KindMismatch`] / [`ServicoCountMismatch`] typed-view
877/// lifts on the sibling per-renderer-error-diagnostic-shape axis: both
878/// families lift a per-renderer duplicated record onto a canonical
879/// substrate-side type, so a future per-target renderer joins the
880/// pattern by re-exporting one alias instead of open-coding another
881/// clone.
882///
883/// The `path` axis carries the sandboxed relative path — the same
884/// [`is_sandboxed_relative_path`] discipline the [`Caixa::validate_code_paths`]
885/// invariant enforces at the manifest-side path axis. No renderer today
886/// runs the predicate against the emit-side per-`RenderedFile.path`
887/// — the paths are picked from substrate-canonical `&'static str`
888/// filename constants ([`FLUX_GITREPOSITORY_YAML_FILENAME`],
889/// [`FLUX_HELMRELEASE_YAML_FILENAME`], [`FLUX_KUSTOMIZATION_YAML_FILENAME`],
890/// [`HELM_CHART_YAML_FILENAME`], [`HELM_VALUES_YAML_FILENAME`]) rather
891/// than author input, so a per-emit-time sandbox check would be
892/// belt-and-suspenders — but the shared type shape makes a future
893/// sandbox-at-emit-time invariant a one-place add across every
894/// per-target renderer.
895///
896/// [cf-flux]: https://docs.rs/caixa-flux
897/// [cf-helm]: https://docs.rs/caixa-helm
898/// [cb]: https://docs.rs/caixa-flux/latest/caixa_flux/fn.cluster_bundle.html
899#[derive(Debug, Clone, PartialEq, Eq)]
900pub struct RenderedFile {
901    /// Sandboxed relative path the substrate writes the artifact under
902    /// (relative to the renderer-chosen output root). Substrate-canonical
903    /// filename constants ([`FLUX_GITREPOSITORY_YAML_FILENAME`] /
904    /// [`FLUX_HELMRELEASE_YAML_FILENAME`] /
905    /// [`FLUX_KUSTOMIZATION_YAML_FILENAME`] for the `caixa-flux`
906    /// [`cluster_bundle`] Flux v2 CR trio, [`HELM_CHART_YAML_FILENAME`] /
907    /// [`HELM_VALUES_YAML_FILENAME`] for the `caixa-helm`
908    /// `lareira-<nome>` chart directory) source every path today.
909    pub path: PathBuf,
910    /// The rendered byte contents — a pre-serialized UTF-8 body every
911    /// downstream writer (`caixa-flux::cluster_bundle`'s
912    /// per-`GitRepository`/`HelmRelease`/`Kustomization` YAML emit,
913    /// `caixa-helm::render_chart_for_servico`'s per-`Chart.yaml`/
914    /// `values.yaml`/`README.md` chart-directory emit) hands to
915    /// `std::fs::write` verbatim under the paired [`Self::path`].
916    pub contents: String,
917}
918
919impl RenderedFile {
920    /// Construct a [`RenderedFile`] from its two axes — the sandboxed
921    /// relative `path` the substrate writes the artifact under and the
922    /// pre-serialized UTF-8 `contents` the paired `std::fs::write`
923    /// hands to that path. Accepts anything convertible into a
924    /// [`PathBuf`] (`&'static str` from the substrate-canonical
925    /// filename constants [`HELM_CHART_YAML_FILENAME`] /
926    /// [`HELM_VALUES_YAML_FILENAME`] / [`FLUX_GITREPOSITORY_YAML_FILENAME`]
927    /// / [`FLUX_HELMRELEASE_YAML_FILENAME`] /
928    /// [`FLUX_KUSTOMIZATION_YAML_FILENAME`] every current per-target
929    /// renderer picks its per-artifact leaf path from, `String` /
930    /// `PathBuf` for future author-supplied paths) and anything
931    /// convertible into [`String`] (the `serde_yaml::to_string` /
932    /// `format!` outputs every current renderer already threads into
933    /// the paired `contents` field).
934    ///
935    /// Lifted from six identical-shape struct-literal construction
936    /// sites — three per-artifact leaves in
937    /// [`caixa-helm`][cf-helm]'s `render_chart_for_servico_with`
938    /// (`Chart.yaml`, `values.yaml`, `README.md`) and three per-CR
939    /// leaves in [`caixa-flux`][cf-flux]'s [`cluster_bundle`][cb]
940    /// (`gitrepository.yaml`, `helmrelease.yaml`,
941    /// `kustomization.yaml`) — each of which open-coded a four-line
942    /// `<Xxx>File { path: PathBuf::from(FILENAME_CONST), contents: <body> }`
943    /// block that re-derived the same `PathBuf::from(&str)` wrap +
944    /// the same two-field assembly. Every existing struct-
945    /// literal construction (the type-alias identity pins at
946    /// [`caixa_flux::tests::bundle_file_alias_resolves_to_caixa_core_rendered_file`]
947    /// / [`caixa_helm::tests::chart_file_alias_resolves_to_caixa_core_rendered_file`],
948    /// the substrate-side field-shape pins in this crate's test
949    /// module) continues to compile — [`RenderedFile::new`] is an
950    /// additive inherent constructor that leaves the `pub path` /
951    /// `pub contents` field visibility untouched, so a future rebrand
952    /// on the record shape (a per-artifact hash / provenance field
953    /// addition, a per-artifact write-mode discriminator once
954    /// per-cluster-writer sandboxing lands) still reaches every
955    /// per-target renderer through this canonical constructor + the
956    /// existing struct-literal pinning by construction. Peer to the
957    /// sibling substrate-side canonical-composer surface
958    /// ([`oci_chart_ref`] / [`cilium_network_policy_name`] /
959    /// [`gateway_api_http_route_name`] / [`lareira_chart_name`]) —
960    /// each is a canonical `&'static fn(&str, …) -> String` composer
961    /// that every per-target renderer routes through instead of
962    /// re-deriving the same encoding inline.
963    ///
964    /// A future per-target renderer (`caixa-otel`'s per-collector-
965    /// config emit, the future `mesh.pleme.io/v1alpha1/Aplicacao` CR
966    /// materializer's per-CR YAML emit, the future per-Supervisor
967    /// reconciler renderer's per-child bundle emit) that constructs a
968    /// [`RenderedFile`] now reaches for [`RenderedFile::new`] and
969    /// participates in the same substrate-side per-artifact-
970    /// construction contract, so any addition here (say, a
971    /// `sandboxed_relative_path` invariant check on `path` at
972    /// construction time, the `is_sandboxed_relative_path`
973    /// discipline the docstring above acknowledges is not yet run at
974    /// emit time) reaches every per-target renderer through one
975    /// caixa-core edit instead of a coordinated six-site rewrite.
976    ///
977    /// [cf-helm]: https://docs.rs/caixa-helm
978    /// [cf-flux]: https://docs.rs/caixa-flux
979    /// [cb]: https://docs.rs/caixa-flux/latest/caixa_flux/fn.cluster_bundle.html
980    #[must_use]
981    pub fn new<P, S>(path: P, contents: S) -> Self
982    where
983        P: Into<PathBuf>,
984        S: Into<String>,
985    {
986        Self {
987            path: path.into(),
988            contents: contents.into(),
989        }
990    }
991}
992
993/// Predicate: find the first ASCII whitespace byte in `s`, or `None` if
994/// none of the string's bytes match `u8::is_ascii_whitespace`.
995///
996/// The canonical drift class this closes across every typed-magnitude
997/// codec in caixa-core (`limits::parse_byte_size` backing
998/// `:limits :memory`, `limits::parse_duration` backing `:limits
999/// :wall-clock`, `limits::parse_millicores` backing `:limits :cpu`,
1000/// `supervisor::duration_codec::parse` backing `:supervisor
1001/// :restart-window` / `:politicas :timeout` / `:politicas
1002/// :circuit-breaker :window`, and `aplicacao::rate_limit_codec::parse`
1003/// backing `:politicas :rate-limit`) is the ASCII subset of Unicode
1004/// `White_Space`: space (`0x20`), tab (`0x09`), LF (`0x0A`), FF
1005/// (`0x0C`), CR (`0x0D`) — the five WhatWG-conformant "ASCII whitespace"
1006/// bytes (deliberately narrower than POSIX's `[:space:]` which also
1007/// admits VT `0x0B`). Every downstream YAML / JSON / TOML parser can
1008/// feed any of these bytes through a quoted-scalar value verbatim, so
1009/// a paste-from-shell-history `"500m "` (trailing space), a
1010/// paste-from-aligned-doc `" 64MiB"` (leading space from YAML-quoted-
1011/// plain-scalar alignment), a paste-from-typography `"30 s"`
1012/// (whitespace between magnitude and unit), a paste-from-indented-doc
1013/// `"\t100/s"` (YAML-block-scalar tab byte), or a multi-line-paste
1014/// `"30s\n"` (trailing LF) all survive the top-level `s.trim()`
1015/// discipline and yield the same typed value at each codec — but
1016/// serde round-trips to a *different* canonical form on the next
1017/// emit, breaking the THEORY.md Part V render-determinism contract
1018/// every typed slot carries.
1019///
1020/// Peer of [`find_non_ascii_whitespace_char`] — the two predicates
1021/// together partition the full Unicode `White_Space` axis (this one
1022/// on the ASCII byte range, its peer on the strictly-complementary
1023/// non-ASCII `char` range), and every typed-magnitude codec in
1024/// caixa-core calls both back-to-back at parse entry so the codec's
1025/// accepted set matches its emitted set on the full axis,
1026/// structurally. Same "single lifted source of truth" discipline the
1027/// peer non-ASCII arm's 1b75b38 landing pinned: drift between any two
1028/// codec sites' ASCII-whitespace-rejection set becomes a single-edit
1029/// fix at this predicate rather than five independent scans
1030/// diverging over time, and a future stricter classification
1031/// (BOM `\u{FEFF}` / ZWSP `\u{200B}` / ZWJ `\u{200D}` — the
1032/// "invisible but not `char::is_whitespace`" class that the
1033/// deliberate exclusion in `find_non_ascii_whitespace_char` leaves
1034/// for a follow-up, if a downstream slot proves those are drift
1035/// classes) can extend at this shared site in one edit rather than
1036/// five. Peer of [`is_dns_1123_label`] / [`is_gateway_api_http_path`]
1037/// / [`is_git_repo_url`] — same "typed-slot's valid set matches its
1038/// codec's accepted set, structurally" discipline carried at the
1039/// codec layer.
1040#[must_use]
1041pub fn find_ascii_whitespace_byte(s: &str) -> Option<u8> {
1042    s.bytes().find(|b| b.is_ascii_whitespace())
1043}
1044
1045/// Predicate: find the first non-ASCII Unicode-`White_Space` character in
1046/// `s`, or `None` if every character lies in the ASCII byte range.
1047///
1048/// The canonical drift class this closes across every typed-magnitude
1049/// codec in caixa-core (`limits::parse_byte_size` backing
1050/// `:limits :memory`, `limits::parse_duration` backing `:limits
1051/// :wall-clock`, `supervisor::duration_codec::parse` backing
1052/// `:supervisor :restart-window` / `:politicas :timeout` /
1053/// `:politicas :circuit-breaker :window`, and
1054/// `aplicacao::rate_limit_codec::parse` backing `:politicas
1055/// :rate-limit`) is the non-ASCII subset of Unicode `White_Space`: NBSP
1056/// (`\u{00A0}`), OGHAM SPACE MARK (`\u{1680}`), the EN-QUAD /
1057/// EM-QUAD / EN-SPACE / EM-SPACE / THREE-PER-EM-SPACE /
1058/// FOUR-PER-EM-SPACE / SIX-PER-EM-SPACE / FIGURE-SPACE /
1059/// PUNCTUATION-SPACE / THIN-SPACE / HAIR-SPACE band
1060/// (`\u{2000}`..=`\u{200A}`), LINE SEPARATOR (`\u{2028}`), PARAGRAPH
1061/// SEPARATOR (`\u{2029}`), NARROW NBSP (`\u{202F}`), MEDIUM
1062/// MATHEMATICAL SPACE (`\u{205F}`), and IDEOGRAPHIC SPACE
1063/// (`\u{3000}`). Every one of these characters is
1064/// [`char::is_whitespace`]`() && !`[`char::is_ascii`]`()`, and every
1065/// one of them is silently stripped by [`str::trim`] at the top of
1066/// each codec's parse entry — `str::trim` uses `char::is_whitespace`,
1067/// which is Unicode `White_Space`, strictly wider than the byte-set
1068/// `u8::is_ascii_whitespace` the pre-gate arm on each codec already
1069/// refuses. So a paste-from-typography `"\u{00A0}64MiB"` (NBSP
1070/// leading) survives the byte-scan (none of its bytes match
1071/// `is_ascii_whitespace`), lands on the top-level `s.trim()` which
1072/// silently strips the NBSP, parses to `64 * 1024 * 1024` bytes, and
1073/// serde round-trips to the *different* canonical `"64MiB"` on next
1074/// emit — breaking the THEORY.md Part V render-determinism contract
1075/// every typed slot carries. Same class on every peer codec:
1076/// `"\u{2028}30s"` (paste-from-web-doc line-separator prefix) →
1077/// `Duration::from_secs(30)` → `"30s"`; `"\u{00A0}100/s"`
1078/// (paste-from-typography NBSP prefix on `:politicas :rate-limit`) →
1079/// `RateLimit { 100, 1s }` → `"100/s"`. The ASCII-whitespace-only
1080/// `is_ascii_whitespace` byte-scan closed on each codec by the
1081/// immediate predecessors (`limits::parse_byte_size` — 24a8ad4;
1082/// `limits::parse_duration` — ebc3a75; `supervisor::duration_codec`
1083/// — a7ae622; `rate_limit_codec` — 1ad7755) covers space (`0x20`),
1084/// tab (`0x09`), LF (`0x0A`), FF (`0x0C`), CR (`0x0D`); this
1085/// predicate closes the strictly-complementary non-ASCII Unicode
1086/// `White_Space` class in one lifted source of truth across all four
1087/// codec sites in one landing — the trajectory the 24a8ad4 commit
1088/// body's `Forward compounding` bullet explicitly named ("the next
1089/// canonical-form-drift trajectory … can land as a single lifted
1090/// predicate across all four codec sites in one follow-up run rather
1091/// than four independent extensions").
1092///
1093/// The predicate is deliberately narrower than "any non-ASCII
1094/// codepoint" — the byte-set restrictions on the accepted magnitude
1095/// (`b.is_ascii_digit()` on the digit-only arm, `is_ascii_alphabetic`
1096/// on the unit-suffix split) already refuse every non-`White_Space`
1097/// non-ASCII codepoint at a downstream arm with a `BadByteMagnitude`
1098/// / `BadDurationMagnitude` / equivalent diagnostic. This predicate's
1099/// job is exclusively to name the drift class — the Unicode
1100/// whitespace subset that survives the byte-scan but that
1101/// `str::trim` silently swallows — so the codec's diagnostic can
1102/// carry the offending [`char`] and its `U+XXXX` codepoint verbatim
1103/// rather than laundering the value through a generic "bad
1104/// magnitude" arm at a downstream site far from the paste-origin.
1105/// Peer of [`is_dns_1123_label`] / [`is_gateway_api_http_path`] /
1106/// [`is_git_repo_url`] — same "typed-slot's valid set matches its
1107/// codec's accepted set, structurally" discipline carried at the
1108/// codec layer.
1109///
1110/// Note that BOM (`\u{FEFF}`, ZERO WIDTH NO-BREAK SPACE) and ZWSP
1111/// (`\u{200B}`, ZERO WIDTH SPACE) are deliberately *outside* this
1112/// predicate's rejection set — both have `char::is_whitespace() ==
1113/// false` per the Unicode `White_Space` property, so `str::trim`
1114/// does *not* silently strip either, and both currently land on the
1115/// downstream `BadByteMagnitude` / `BadDurationMagnitude` arm at
1116/// parse time with the byte-shape diagnostic intact. Adding them
1117/// here would over-fire on an accepted-diagnostic class already
1118/// closed at a peer arm — the render-determinism contract is
1119/// unbroken on those inputs today.
1120#[must_use]
1121pub fn find_non_ascii_whitespace_char(s: &str) -> Option<char> {
1122    s.chars().find(|c| c.is_whitespace() && !c.is_ascii())
1123}
1124
1125/// Predicate: `s` carries a leading-zero-padded magnitude — its length
1126/// exceeds one byte and its first byte is ASCII `'0'`.
1127///
1128/// The canonical drift class this closes across every typed-magnitude
1129/// codec in caixa-core (`limits::parse_byte_size` backing `:limits
1130/// :memory` — cea9a78; `limits::parse_duration` backing `:limits
1131/// :wall-clock` — 39762d7; `limits::parse_millicores` backing
1132/// `:limits :cpu` — the sixth codec surface;
1133/// `supervisor::duration_codec::parse` backing `:supervisor
1134/// :restart-window` / `:politicas :timeout` / `:politicas
1135/// :circuit-breaker :window` — 9178904; and
1136/// `aplicacao::rate_limit_codec::parse` backing `:politicas
1137/// :rate-limit` — 4f46830) is the leading-zero-padded magnitude
1138/// shape: every downstream typed-magnitude codec's `render_*`
1139/// canonicalizer emits the leading-zero-stripped form, so a
1140/// leading-zero magnitude (`"030s"`, `"0100/s"`, `"0500m"`,
1141/// `"0064MiB"`, `"01h"`) round-trips through `render_*` to a
1142/// *different* canonical string on the next emit (`"30s"`, `"100/s"`,
1143/// `"500m"`, `"64MiB"`, `"1h"`) — breaking the THEORY.md Part V
1144/// render-determinism contract every typed slot carries the same way
1145/// the leading-`+` shape did before the digit-only arm landed.
1146///
1147/// The predicate deliberately admits the single-byte magnitude `"0"`
1148/// (returning `false`) — every codec's `render_*` canonicalizer emits
1149/// `"0"` / `"0s"` / `"0m"` / `"0/s"` verbatim for the zero magnitude,
1150/// so the single-byte form round-trips losslessly through the codec
1151/// layer. The downstream semantic-zero gates
1152/// ([`crate::LimitsError::MemoryZero`],
1153/// [`crate::LimitsError::WallClockZero`],
1154/// [`crate::LimitsError::CpuZero`],
1155/// [`crate::SupervisorError::ZeroRestartWindow`],
1156/// [`crate::AplicacaoError::PolicyTimeoutZero`],
1157/// [`crate::AplicacaoError::PolicyCircuitBreakerWindowZero`],
1158/// [`crate::AplicacaoError::PolicyRateLimitZero`]) refuse the
1159/// semantic-zero authoring at the typed-validate layer above; the
1160/// codec-layer / typed-validate-layer partition between
1161/// canonical-form drift (this arm) and semantic-zero (the downstream
1162/// gate) remains stable across every codec site.
1163///
1164/// Peer of [`find_ascii_whitespace_byte`] /
1165/// [`find_non_ascii_whitespace_char`] on the same
1166/// canonical-form-drift axis at the codec layer: those two predicates
1167/// close the whitespace drift class (paste-from-shell-history /
1168/// paste-from-typography), this one closes the leading-zero-padding
1169/// drift class (paste-from-fixed-width-alignment /
1170/// paste-from-columnar-report). Same "single lifted source of truth"
1171/// discipline: drift between any two codec sites' leading-zero
1172/// rejection set becomes a single-edit fix at this predicate rather
1173/// than five independent `s.len() > 1 && s.as_bytes()[0] == b'0'`
1174/// scans diverging over time. A future stricter classification
1175/// closing at this shared site (a hypothetical `"00"` shape whose
1176/// diagnostic distinguishes explicit-zero-padding from the accepted
1177/// canonical `"0"`, or a future higher base like `"0x0100"` whose
1178/// magnitude prefix would trip this arm before the digit-only gate
1179/// catches the `x`) extends at one location rather than five. Peer of
1180/// [`is_dns_1123_label`] / [`is_gateway_api_http_path`] /
1181/// [`is_git_repo_url`] — same "typed-slot's valid set matches its
1182/// codec's accepted set, structurally" discipline carried at the
1183/// codec layer.
1184#[must_use]
1185pub fn is_leading_zero_padded_magnitude(s: &str) -> bool {
1186    s.len() > 1 && s.as_bytes()[0] == b'0'
1187}
1188
1189/// Predicate: `s` is a non-empty digit-only magnitude — every byte is
1190/// an ASCII digit `[0-9]`.
1191///
1192/// The canonical drift class this closes across every typed-magnitude
1193/// codec in caixa-core (`limits::parse_byte_size` backing
1194/// `:limits :memory`, `limits::parse_duration` backing `:limits
1195/// :wall-clock`, `limits::parse_millicores` backing `:limits :cpu`,
1196/// `supervisor::duration_codec::parse` backing `:supervisor
1197/// :restart-window` / `:politicas :timeout` / `:politicas
1198/// :circuit-breaker :window`, and `aplicacao::rate_limit_codec::parse`
1199/// backing `:politicas :rate-limit`) is the non-digit-only magnitude
1200/// shape: every downstream typed-magnitude codec's `render_*`
1201/// canonicalizer emits a bare integer magnitude with no leading sign
1202/// (`+` / `-`), no decimal point, and no exponent, so a signed
1203/// magnitude (`"+30s"`, `"+500m"`, `"+100/s"`, `"+64MiB"`) or a
1204/// fractional / decimal magnitude (`"1.5s"`, `"0.5m"`, `"1.0/s"`,
1205/// `"1.5KiB"`) round-trips through `render_*` to a *different*
1206/// canonical string on the next emit (`"30s"`, `"500m"`, `"100/s"`,
1207/// `"64MiB"`, `"1500ms"`, `"30s"`, `"1/s"`, `"1KiB"`) — breaking the
1208/// THEORY.md Part V render-determinism contract every typed slot
1209/// carries.
1210///
1211/// The predicate deliberately treats the empty string as non-digit-only
1212/// (returning `false`) so an upstream codec that hasn't already
1213/// refused the empty-magnitude shape on its own `Empty*` / `Bad*` arm
1214/// still routes empty input to the non-canonical branch rather than
1215/// silently accepting it via the vacuous `bytes().all(_)` truth. Every
1216/// current codec site refuses empty magnitudes on a prior arm before
1217/// this predicate is consulted (`limits::parse_byte_size`'s `num_trim`
1218/// empty branch, `limits::parse_duration`'s `num_trim` empty branch,
1219/// `limits::parse_millicores`'s `magnitude.is_empty()` branch,
1220/// `supervisor::duration_codec::parse`'s `num_trim` empty branch,
1221/// `aplicacao::rate_limit_codec::parse`'s `rate_trim` empty branch),
1222/// so on the reachable inputs the empty-string clause is a no-op; the
1223/// clause is defense-in-depth for a future codec that reaches for this
1224/// predicate before landing its own upstream empty-magnitude arm.
1225///
1226/// The predicate deliberately admits the single-byte magnitude `"0"`
1227/// (returning `true`) — every codec's `render_*` canonicalizer emits
1228/// `"0"` / `"0s"` / `"0m"` / `"0/s"` verbatim for the zero magnitude,
1229/// so the single-byte form round-trips losslessly through the codec
1230/// layer. The downstream semantic-zero gates
1231/// ([`crate::LimitsError::MemoryZero`],
1232/// [`crate::LimitsError::WallClockZero`],
1233/// [`crate::LimitsError::CpuZero`],
1234/// [`crate::SupervisorError::ZeroRestartWindow`],
1235/// [`crate::AplicacaoError::PolicyTimeoutZero`],
1236/// [`crate::AplicacaoError::PolicyCircuitBreakerWindowZero`],
1237/// [`crate::AplicacaoError::PolicyRateLimitZero`]) refuse the
1238/// semantic-zero authoring at the typed-validate layer above; the
1239/// codec-layer / typed-validate-layer partition between
1240/// canonical-form drift (this arm) and semantic-zero (the downstream
1241/// gate) remains stable across every codec site.
1242///
1243/// Peer of [`find_ascii_whitespace_byte`] /
1244/// [`find_non_ascii_whitespace_char`] /
1245/// [`is_leading_zero_padded_magnitude`] on the same
1246/// canonical-form-drift axis at the codec layer: those three
1247/// predicates close the whitespace and leading-zero-padding drift
1248/// classes (paste-from-shell-history / paste-from-typography /
1249/// paste-from-fixed-width-alignment / paste-from-columnar-report),
1250/// this one closes the leading-sign / fractional / decimal /
1251/// exponent-shape drift class (paste-from-signed-report /
1252/// paste-from-floating-point-source / paste-from-scientific-notation).
1253/// Same "single lifted source of truth" discipline: drift between any
1254/// two codec sites' digit-only rejection set becomes a single-edit
1255/// fix at this predicate rather than five independent
1256/// `!<var>.is_empty() && <var>.bytes().all(|b| b.is_ascii_digit())`
1257/// scans diverging over time. Peer of [`is_dns_1123_label`] /
1258/// [`is_gateway_api_http_path`] / [`is_git_repo_url`] — same
1259/// "typed-slot's valid set matches its codec's accepted set,
1260/// structurally" discipline carried at the codec layer.
1261#[must_use]
1262pub fn is_digit_only_magnitude(s: &str) -> bool {
1263    !s.is_empty() && s.bytes().all(|b| b.is_ascii_digit())
1264}
1265
1266/// K8s DNS-1123 label rule's max length, in bytes — the floor each
1267/// apiserver-side schema enforces independently on every `metadata.name`
1268/// / Service name / label value axis a validated identifier lands in.
1269///
1270/// Per-axis breakdown of why 63 is the strictest among the rules each
1271/// validated DNS-1123-label-shaped identifier passes through:
1272///
1273///   * `:membros :caixa` lands as the rendered programs.yaml entry's
1274///     `name:` (consumed by `lareira-fleet-programs` to derive the
1275///     `wasm.pleme.io/v1alpha1/ComputeUnit.metadata.name`), as the K8s
1276///     [`Service`][svc] `metadata.name` the future `app-operator`
1277///     provisions per-member (DNS-1035 label rule:
1278///     `[a-z]([-a-z0-9]*[a-z0-9])?` max 63), as the
1279///     [`LABEL_PROGRAM`] label value (K8s label value rule:
1280///     `[a-z0-9]([-a-z0-9_.]*[a-z0-9])?` max 63), and as a component of
1281///     the composed `<aplicacao>-<de>-to-<para>` `CiliumNetworkPolicy`
1282///     `metadata.name`.
1283///   * `:placement :clusters` lands as the K8s context name keying
1284///     every per-cluster `kubeconfig`, as the `clusters[]` filter the
1285///     `lareira-fleet-programs` aggregator applies to scope programs
1286///     to their owning cluster, and as the namespace prefix /
1287///     `cluster.x-k8s.io/v1beta1/Cluster.metadata.name` cluster
1288///     identity the future M4 cross-cluster fan-out emits per entry —
1289///     all DNS-1123-label territory.
1290///   * `:children :caixa` lands as the rendered
1291///     `wasm.pleme.io/v1alpha1/ComputeUnit.metadata.name` per child the
1292///     supervisor materializes, as the [`LABEL_PROGRAM`] label value on
1293///     every emitted child's pod identity, and as the per-child
1294///     [`Service`][svc] `metadata.name` the future wasm-operator
1295///     provisions — every K8s apiserver-side schema on each landing site
1296///     enforces the same DNS-1123 label rule on admission.
1297///
1298/// Lifted to one const so a future identifier axis reaching for the
1299/// same rule (the future per-Servico `:nome` gate at the Caixa-load
1300/// boundary, the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
1301/// per-member / per-cluster validators, the future per-Aplicacao
1302/// `:nome` gate when `feira init` lands DNS-1123 enforcement on the
1303/// scaffold's `--nome` flag) reads the limit from one place.
1304///
1305/// [svc]: https://kubernetes.io/docs/concepts/services-networking/service/
1306pub const DNS_1123_LABEL_MAX_LEN: usize = 63;
1307
1308/// Predicate: assert that `s` is a valid K8s DNS-1123 label. The
1309/// contract — exactly the regex the K8s apiserver enforces on every
1310/// `metadata.name` / Service name / label value via OpenAPI v3 admission
1311/// validation, `[a-z0-9]([-a-z0-9]*[a-z0-9])?` with a 63-byte cap:
1312///
1313///   - 1..=63 bytes ([`DNS_1123_LABEL_MAX_LEN`] cap);
1314///   - lowercase ASCII alphanumeric + hyphen (`[a-z0-9-]` only; no
1315///     uppercase — K8s rejects, no underscore — DNS-1123 forbids, no
1316///     dot — a single label is not a subdomain, no Unicode/IDN — must
1317///     be pre-encoded);
1318///   - non-hyphen ASCII alphanumeric at both label boundaries
1319///     (no `-foo`, no `foo-`).
1320///
1321/// Returns the parser-shaped reason on rejection (without wrapping in
1322/// any error variant) so each per-axis caller — `validate_membro_caixa`
1323/// for `:membros :caixa`, `validate_placement_cluster` for
1324/// `:placement :clusters`, `validate_child_caixa` for `:children :caixa`,
1325/// every future per-axis lift (the per-Servico `:nome` gate at the
1326/// Caixa-load boundary, the M4 CR materializer's per-member /
1327/// per-cluster validators) — wraps the same reason in its own typed
1328/// `*Error::*Invalid { <axis>, reason }` variant. The reason wording is
1329/// axis-agnostic ("DNS-1123 labels allow only `[a-z0-9-]`") so every
1330/// call site reading the same diagnostic points at the same rule —
1331/// drift between any two axes' rule enforcement is a build error
1332/// visible at this predicate, not a per-renderer "this passed validate
1333/// but failed admission" surprise.
1334///
1335/// Empty input is rejected at the call site (each axis has its own
1336/// narrower `*Empty` variant — [`crate::AplicacaoError::MembroCaixaEmpty`],
1337/// [`crate::AplicacaoError::PlacementClusterEmpty`],
1338/// [`crate::SupervisorError::EmptyChildName`]) before this predicate
1339/// is consulted, mirroring `validate_entrada_host`'s empty-first
1340/// cascade (c7d05ec). The predicate body re-checks empty defensively
1341/// so it can be called from any future call site without a shape-
1342/// mismatch footgun — the same "defensive re-check" discipline every
1343/// peer value-shape predicate ([`is_gateway_api_http_path`] line 730,
1344/// [`is_wit_world_ref`] line 937, [`is_nats_subject`] line 1387,
1345/// [`is_wasi_keyvalue_slot`] line 1612, [`is_git_ref_name`] line 1777)
1346/// carries. Without the defensive re-check, calling
1347/// `is_dns_1123_label("")` panics at `bytes[0]` on the empty-slice
1348/// index below (`bytes[0].is_ascii_alphanumeric()` — the boundary
1349/// arm's `s.as_bytes()[0]` access reads past the end of the empty
1350/// slice), a `panic!` far from the source caixa.lisp on any future
1351/// call site that misses the pre-check. The peer predicates all
1352/// return `Err("must not be empty")` on this input; this arm brings
1353/// `is_dns_1123_label` in line with the same defensive contract.
1354///
1355/// Lifted from `caixa-core::aplicacao` (where it was first inlined for
1356/// `:membros :caixa` in 3f9d7a0 and then reused for `:placement :clusters`
1357/// in 6cbb900) so the third axis reaching for the rule (`:children
1358/// :caixa` on the supervisor tree) lands as a thin five-line wrapper
1359/// rather than re-inlining 40 lines of regex enforcement. The
1360/// "before its third occurrence" boundary the PRIME DIRECTIVE
1361/// duplication-budget rule draws (THEORY.md §I.3.5: "the duplication
1362/// budget is zero") promotes the predicate to a typed substrate-side
1363/// primitive on the same trajectory the M2-overlay and label-selector
1364/// helpers (9e3a057, 9d09cfb, 9dbeafd, 31455a7, 07a4544) already follow.
1365///
1366/// # Errors
1367///
1368/// Returns the parser-shaped reason naming the specific violation
1369/// (length / boundary / character-class), without wrapping in any
1370/// error variant — every caller maps the same `String` into its own
1371/// typed `*Invalid { <axis>, reason }` enum variant.
1372pub fn is_dns_1123_label(s: &str) -> Result<(), String> {
1373    if s.is_empty() {
1374        return Err("must not be empty".to_string());
1375    }
1376    if s.len() > DNS_1123_LABEL_MAX_LEN {
1377        return Err(format!(
1378            "exceeds DNS-1123 label max length of {DNS_1123_LABEL_MAX_LEN} bytes \
1379             (got {} bytes; the K8s apiserver rejects longer names at admission \
1380             time on every Service / Pod / CR `metadata.name` axis)",
1381            s.len()
1382        ));
1383    }
1384    let bytes = s.as_bytes();
1385    if !bytes[0].is_ascii_alphanumeric() || !bytes[bytes.len() - 1].is_ascii_alphanumeric() {
1386        return Err("must start and end with an ASCII alphanumeric character \
1387                    (no leading or trailing `-`; DNS-1123 label rule)"
1388            .to_string());
1389    }
1390    for &b in bytes {
1391        let valid = b.is_ascii_digit() || b.is_ascii_lowercase() || b == b'-';
1392        if !valid {
1393            let msg = if b.is_ascii_uppercase() {
1394                format!(
1395                    "contains uppercase character {ch:?} (K8s DNS-1123 label \
1396                     names are lowercase-only; use {lower:?})",
1397                    ch = b as char,
1398                    lower = s.to_ascii_lowercase()
1399                )
1400            } else if b == b'_' {
1401                "contains `_` (DNS-1123 labels allow only `[a-z0-9-]`; use `-` \
1402                 instead)"
1403                    .to_string()
1404            } else if b == b'.' {
1405                "contains `.` (a single DNS-1123 label is not a subdomain; \
1406                 split into separate entries or use `-` to namespace)"
1407                    .to_string()
1408            } else {
1409                format!(
1410                    "contains invalid character {ch:?} (DNS-1123 labels allow \
1411                     only `[a-z0-9-]`)",
1412                    ch = b as char
1413                )
1414            };
1415            return Err(msg);
1416        }
1417    }
1418    Ok(())
1419}
1420
1421/// K8s Gateway API v1 `HTTPPathMatch.value` max length, in bytes —
1422/// the apiserver-side `OpenAPI` schema's `maxLength: 1024` cap. Lifted
1423/// to a typed const so a future axis reaching for the same bound (the
1424/// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-path
1425/// validator, the future per-`HTTPRouteRule` per-path-match emission
1426/// when M4 lands per-rule overrides, the future `:politicas`-derived
1427/// per-edge HTTP path overlay's per-path validator) reads the limit
1428/// from one place. The two landed call sites — `:entrada :paths`
1429/// entries (caixa-mesh's `HTTPRoute.spec.rules[].matches[].path.value`
1430/// emission) and `:contratos :endpoint` (caixa-mesh's Cilium L7
1431/// `path:` rule emission, caixa-mesh/src/lib.rs:311) — both inherit
1432/// the same cap; drift between either landing site and the K8s CRD
1433/// schema surfaces at this one const.
1434pub const GATEWAY_API_HTTP_PATH_MAX_LEN: usize = 1024;
1435
1436/// K8s Gateway API v1 `Listener.hostname` and
1437/// `HTTPRoute.spec.hostnames[]` max length, in bytes — the apiserver-side
1438/// `OpenAPI` schema's `maxLength: 253` cap, ultimately the RFC 1035 / RFC
1439/// 1123 DNS name limit (255 wire bytes minus the trailing-dot + one length
1440/// prefix). Lifted to a typed const so a future axis reaching for the same
1441/// bound (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
1442/// per-`:entrada :host` validator, the future per-`Certificate` SAN emitter
1443/// keying off `:entrada :host` for cert-manager, the future
1444/// multi-`:entrada` host-collision gate when M4 lands `:entrada` as a
1445/// `Vec`) reads the limit from one place. The sole landed call site — the
1446/// `:entrada :host` axis's total-length gate at
1447/// [`crate::AplicacaoSpec::validate`] via `validate_entrada_host` — reads
1448/// this constant verbatim; drift between the landing site and the K8s CRD
1449/// schema surfaces at this one const rather than a per-renderer "this
1450/// passed validate but failed admission" surprise.
1451///
1452/// Peer of [`GATEWAY_API_HTTP_PATH_MAX_LEN`] on the sibling per-route
1453/// path-value cap axis — both are apiserver-side `maxLength:` bounds on
1454/// Gateway API v1 landing sites the pleme-io substrate emits, both lift
1455/// to `caixa-core::render` so the M4 CR materializer's per-axis
1456/// validators (per-host, per-path) read from one place. Same "typed const
1457/// so the bound has exactly one source of truth" discipline every peer
1458/// upper bound in this crate carries
1459/// ([`DNS_1123_LABEL_MAX_LEN`], [`NATS_SUBJECT_MAX_LEN`],
1460/// [`WASI_KV_SLOT_MAX_LEN`], [`WIT_IDENT_MAX_LEN`],
1461/// [`crate::LIMITS_MEMORY_WASM32_MAX_BYTES`],
1462/// [`crate::POLICY_TIMEOUT_MAX`], [`crate::POLICY_RETRIES_MAX`]).
1463///
1464/// The per-label max within the hostname is [`DNS_1123_LABEL_MAX_LEN`]
1465/// (63): every `.`-separated label in a Gateway API v1 Hostname is a
1466/// DNS-1123 label under the apiserver's OpenAPI regex
1467/// `[a-z0-9]([-a-z0-9]*[a-z0-9])?`, so drift between the total-length
1468/// cap here and the per-label cap on the peer constant is impossible by
1469/// construction.
1470pub const GATEWAY_API_HOSTNAME_MAX_LEN: usize = 253;
1471
1472/// K8s Gateway API v1 `Gateway.spec.listeners[].port` — the substrate's
1473/// canonical port scalar every Aplicacao-level
1474/// [`caixa_mesh::gateway_routes`][cm] -emitted `Gateway`'s sole per-
1475/// listener HTTP-listener-port axis reads from. IANA-registered as the
1476/// well-known `http` service port (RFC 9110 §4.2.2 / RFC 3986 §3.2.3 —
1477/// the port implied by an `http://<host>/…` URL when the authority
1478/// carries no explicit `:<port>` selector), so the substrate's external
1479/// `:entrada` HTTP flow surfaces at `http://<entrada.host>/` with no
1480/// per-client port override.
1481///
1482/// Semantically distinct from [`crate::DEFAULT_SERVICO_PORT`] (8080)
1483/// on the sibling per-Servico L4 axis — that constant is the port each
1484/// in-cluster Servico's `pleme-computeunit`-emitted K8s `Service`
1485/// listens on (the destination side of every mesh flow); this constant
1486/// is the port the Aplicacao's own external Gateway listens on (the
1487/// external ingress side, K8s-Gateway-API-CRD-controller-visible).
1488/// Two axes, two lifts — a future rebrand on either axis (the
1489/// substrate moving external HTTP to `:443` under mTLS-terminated
1490/// listeners, the substrate moving in-cluster Servicos onto `:80`
1491/// once the well-known port is freed) lands on its own canonical
1492/// const without coupling either axis to the other's rebrand cycle.
1493///
1494/// Until this lift landed the value `80` lived at one production-code
1495/// call site: the `listener.insert(KUBE_KEY_PORT, …)` call at
1496/// `caixa-mesh/src/lib.rs:2588` inside
1497/// [`caixa_mesh::gateway_routes`][cm]'s per-Aplicacao `Gateway`
1498/// emitter. A future Gateway API v1 promotion moving the well-known
1499/// external HTTP listener to a substrate-chosen alternative — the
1500/// substrate moving to `:443` once cert-manager-issued
1501/// per-`:entrada :host` certificates land and the external listener
1502/// becomes HTTPS-by-default (matching the mTLS-by-default trajectory
1503/// [`crate::DEFAULT_SERVICO_PORT`]'s docstring names), a per-cluster
1504/// override the operator pins through a future `:entrada :port` slot
1505/// promoted from Servico-side (`:entrada :port` today's typed slot
1506/// names the destination Servico port, not the Gateway listener
1507/// port) — without a coordinated edit would silently emit a
1508/// `Gateway` whose per-listener HTTP-listener-port axis the K8s
1509/// Gateway API v1 controller admits at the drifted port and the
1510/// gateway-class-controller (Cilium's Envoy sidecar today) opens on
1511/// the drifted port too, so every external `:entrada` HTTP flow
1512/// drops at the first hop with no diagnostic naming the drift root
1513/// cause. Lifting the literal to a shared typed `u16` const closes
1514/// the drift footgun structurally — every consumer reads from the
1515/// same lifted constant, so any rebrand reaches every site by
1516/// construction.
1517///
1518/// Mirrors the [`crate::DEFAULT_SERVICO_PORT`] lift (a085b26) on the
1519/// peer per-renderer canonical-K8s-port-axis typed `u16` const — both
1520/// are IANA-registered service-port scalars the substrate's mesh
1521/// renderer emits under a K8s CRD's `port:` axis, both lift to
1522/// `caixa-core::render` so any future substrate-side port migration
1523/// (external HTTP `:80 → :443`, in-cluster Servico `:8080 → :80`)
1524/// lands at exactly one const per axis. Same "typed const so the
1525/// scalar has exactly one source of truth" discipline every peer
1526/// scalar in this crate carries ([`GATEWAY_API_HOSTNAME_MAX_LEN`],
1527/// [`GATEWAY_API_HTTP_PATH_MAX_LEN`], [`DNS_1123_LABEL_MAX_LEN`],
1528/// [`WIT_IDENT_MAX_LEN`]).
1529///
1530/// [cm]: ../../caixa_mesh/fn.gateway_routes.html
1531pub const GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT: u16 = 80;
1532
1533/// K8s Gateway API v1 `Gateway.spec.listeners[].name` — the substrate's
1534/// canonical author-chosen listener-name scalar every Aplicacao-level
1535/// [`caixa_mesh::gateway_routes`][cm] -emitted `Gateway`'s sole per-
1536/// listener name-discriminator axis reads from. Gateway API v1's
1537/// `Listener.name` is `SectionName`-typed (a required DNS-1123 label
1538/// unique within the parent Gateway's listener list — see the upstream
1539/// docs at
1540/// <https://gateway-api.sigs.k8s.io/api-types/gateway/#listeners> and
1541/// the type reference at
1542/// <https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.SectionName>);
1543/// downstream `HTTPRoute.spec.parentRefs[].sectionName` selectors bind
1544/// to this exact byte-string when the author wants to attach a route
1545/// to one specific listener out of a multi-listener Gateway. The V0
1546/// substrate emits exactly one HTTP listener per Aplicacao, so the
1547/// name is arbitrary from the CRD's perspective — the substrate picks
1548/// the byte-string `"http"` as the canonical short name (matching the
1549/// listener's protocol axis [`GATEWAY_API_PROTOCOL_HTTP`] in kind, but
1550/// not in bytes: this is the lowercase-ASCII listener-name identifier,
1551/// the sibling protocol scalar is the uppercase-ASCII
1552/// `ProtocolType` enum value the Gateway API v1 CRD schema pins).
1553///
1554/// Semantically distinct from every peer `"http"`-shaped byte-string
1555/// in the substrate:
1556///
1557///   - [`crate::GATEWAY_API_PROTOCOL_HTTP`] (`"HTTP"`) — the listener's
1558///     `spec.listeners[].protocol` `ProtocolType` enum value the
1559///     Gateway API v1 CRD schema pins to the uppercase-ASCII spelling;
1560///     this constant names the arbitrary author-chosen listener-name
1561///     identifier at the sibling `spec.listeners[].name` axis instead,
1562///     and the two carry different case shapes on purpose;
1563///   - [`crate::CILIUM_KEY_HTTP`] (`"http"`) — the Cilium CRD's per-
1564///     `toPorts[]` L7-HTTP-rule-list-discriminator container-axis key
1565///     (`spec.ingress[].toPorts[].rules.http`), a CRD-schema-pinned
1566///     field name the Cilium project's per-CRD-schema-migration cycle
1567///     controls; this constant names an Aplicacao-side arbitrary
1568///     listener-name at a distinct K8s Gateway API CRD path, and the
1569///     substrate can move it without touching the Cilium schema.
1570///
1571/// Byte-identical to [`CILIUM_KEY_HTTP`] today (both spell out the
1572/// four ASCII bytes `h`, `t`, `t`, `p`), but the two lifted axes name
1573/// semantically distinct surfaces — a future substrate-side listener-
1574/// name rebrand (say, `"http" → "http-v1"` once the Aplicacao renders
1575/// multiple listeners under the HTTPS-by-default trajectory) must
1576/// reach this consumer without dragging the Cilium schema key with it.
1577///
1578/// Until this lift landed the value `"http"` lived at one production-
1579/// code call site: the `listener.insert(GATEWAY_API_KEY_NAME, "http")`
1580/// call inside [`caixa_mesh::gateway_routes`][cm]'s per-Aplicacao
1581/// `Gateway` emitter. A future Gateway API v2 rebrand of the well-
1582/// known short listener-name (a substrate-side migration to a longer
1583/// discriminator once multi-listener Gateways ship, an operator-pinned
1584/// override the future `:entrada :listener-name` slot promotes) —
1585/// without a coordinated edit — would silently emit a `Gateway`
1586/// whose listener carries the drifted identifier, so every downstream
1587/// `HTTPRoute` `sectionName` selector authored against the substrate's
1588/// prior canonical name misses its listener, and every external
1589/// `:entrada` HTTP flow drops at attachment time with no diagnostic
1590/// naming the listener-name drift root cause. Lifting the literal to
1591/// a shared typed `&'static str` const closes the drift footgun
1592/// structurally — every consumer reads from the same lifted constant,
1593/// so any rebrand reaches every site by construction.
1594///
1595/// Mirrors the [`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`] lift
1596/// (cd60fde) on the peer per-listener HTTP-listener-port scalar-axis —
1597/// both are Aplicacao-side substrate-canonical scalar-value pins the
1598/// sole per-Aplicacao `Gateway` emitter reaches for, and both lift to
1599/// `caixa-core::render` so a future substrate-side rebrand on either
1600/// listener axis (`:port` → `:443`, `:name` → `"http-v1"`) lands at
1601/// exactly one const per axis. Same "typed const so the scalar has
1602/// exactly one source of truth" discipline every peer scalar in this
1603/// crate carries ([`DEFAULT_GATEWAY_CLASS_NAME`],
1604/// [`GATEWAY_API_PROTOCOL_HTTP`],
1605/// [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`]).
1606///
1607/// [cm]: ../../caixa_mesh/fn.gateway_routes.html
1608pub const GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME: &str = "http";
1609
1610/// K8s Gateway API v1 `HTTPRoute.spec.rules[].matches[].path.value`
1611/// substrate-side catch-all path — the fallback URL path every
1612/// Aplicacao-level [`caixa_mesh::gateway_routes`][cm] -emitted
1613/// `HTTPRoute` renders when the typed `:entrada :paths` slot is
1614/// empty, so an author who declares an external `:entrada` but no
1615/// per-path rule surface still gets a route whose sole
1616/// `HTTPPathMatch` matches every incoming request under the
1617/// paired [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`] discriminator.
1618/// K8s Gateway API v1's `PathPrefix` matcher over the bare-root
1619/// `"/"` is the canonical catch-all shape — the upstream docs at
1620/// <https://gateway-api.sigs.k8s.io/api-types/httproute/#path-based-routing>
1621/// pin the `PathPrefix "/"` combination as the "match anything the
1622/// listener admits" idiom every gateway-class controller (Cilium's
1623/// Envoy today, Envoy Gateway / Istio Gateway on the peer
1624/// controllers) treats as the equivalent of "no path predicate"
1625/// under the CRD schema.
1626///
1627/// Until this lift landed the value `"/"` lived at one production-
1628/// code call site: the `vec!["/"]` fallback arm inside
1629/// [`caixa_mesh::gateway_routes`][cm]'s `let paths: Vec<&str> =
1630/// if entrada.paths.is_empty() { vec!["/"] } else { … }` branch, the
1631/// sole per-Aplicacao HTTPRoute per-rule path-list resolver that
1632/// surfaces the catch-all URL path whenever the typed `:entrada
1633/// :paths` list is empty. A future substrate-side rebrand of the
1634/// catch-all shape — a hypothetical migration to Gateway API v2's
1635/// `Exact ""` idiom, an operator-pinned per-Aplicacao override the
1636/// future `:entrada :default-path` slot promotes, a per-controller
1637/// variant that treats `"/"` as a literal prefix rather than the
1638/// catch-all — without a coordinated edit would silently emit an
1639/// `HTTPRoute` whose sole path-match predicate rejects every
1640/// incoming request at the drifted shape, so every external
1641/// `:entrada` HTTP flow drops at the first hop with no diagnostic
1642/// naming the catch-all-path drift root cause. Lifting the literal
1643/// to a shared typed `&'static str` const closes the drift footgun
1644/// structurally — every consumer reads from the same lifted constant,
1645/// so any rebrand reaches every site by construction.
1646///
1647/// Semantically distinct from every peer HTTP-path byte-string in the
1648/// substrate. The typed [`Entrada::paths`] admission grammar
1649/// ([`is_gateway_api_http_path`] + [`GATEWAY_API_HTTP_PATH_MAX_LEN`])
1650/// admits the bare-root `"/"` at the author's slot; this constant
1651/// names the substrate's *emit-side* choice for the same byte-string
1652/// at the *no-author-input* path — the two axes carry the identical
1653/// shape today by design (the substrate's catch-all round-trips
1654/// through the same admission grammar the author's explicit `"/"`
1655/// would clear), and the paired
1656/// [`gateway_api_default_http_route_path_carries_valid_gateway_api_http_path_shape`]
1657/// cross-axis pin closes the invariant at build time.
1658///
1659/// Mirrors the [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] (a12dcdd) /
1660/// [`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`] (cd60fde) lifts on the
1661/// peer per-listener substrate-canonical scalar-value axes — all
1662/// three are Aplicacao-side substrate-canonical scalar-value pins the
1663/// sole per-Aplicacao mesh emitter reaches for at a K8s Gateway API
1664/// v1 CRD sub-path, and all three lift to `caixa-core::render` so a
1665/// future substrate-side rebrand on any one axis lands at exactly one
1666/// const per axis. Same "typed const so the scalar has exactly one
1667/// source of truth" discipline every peer scalar in this crate
1668/// carries ([`DEFAULT_GATEWAY_CLASS_NAME`],
1669/// [`GATEWAY_API_PROTOCOL_HTTP`],
1670/// [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`]).
1671///
1672/// [cm]: ../../caixa_mesh/fn.gateway_routes.html
1673pub const GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH: &str = "/";
1674
1675/// Predicate: assert that `path` is a valid HTTP path under both the
1676/// K8s Gateway API v1 `HTTPPathMatch.value` admission grammar AND the
1677/// Cilium L7 `path:` rule grammar — the two landing sites every
1678/// validated pleme-io HTTP-shaped path lands in. The contract:
1679///
1680///   - 1..=[`GATEWAY_API_HTTP_PATH_MAX_LEN`] (1024) bytes;
1681///   - leading `/` (the `PathPrefix` invariant — pre-checked at the
1682///     call site by each axis's narrower `*NotAbsolute` variant;
1683///     re-checked here so the predicate is usable from any future
1684///     call site without a shape-mismatch footgun);
1685///   - no consecutive `/` characters (HTTP path matchers reject
1686///     `//` — collapse to a single `/`);
1687///   - no `/./` or `/../` segments (and no trailing `/.` or `/..`) —
1688///     path-traversal and no-op segments are rejected outright;
1689///   - no `?` (query separator: queries are matched separately via
1690///     `HTTPRoute` `queryParams`, never in the path);
1691///   - no `#` (fragment separator: fragments are client-side and
1692///     never reach the gateway);
1693///   - no whitespace (space, tab — must be percent-encoded as `%20`);
1694///   - no ASCII control characters (`0x00..0x1F`, `0x7F`);
1695///   - no non-ASCII bytes (`>= 0x80`) — RFC 3986 requires `%XX`
1696///     percent-encoding for anything outside the ASCII unreserved +
1697///     reserved set;
1698///   - no printable-ASCII byte outside the K8s Gateway API
1699///     `HTTPPathMatch.value` apiserver-side `OpenAPI` regex
1700///     `^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$`
1701///     accepted set — namely `"` `<` `>` `[` `\` `]` `^` `` ` `` `{`
1702///     `|` `}`. These eleven bytes are printable ASCII but RFC 3986's
1703///     `pchar = unreserved / pct-encoded / sub-delims / ":" / "@"`
1704///     grammar excludes them, so the apiserver rejects them at
1705///     admission time on every `HTTPRoute.spec.rules[].matches[].
1706///     path.value` landing site and the Cilium L7 path matcher
1707///     refuses them too. Percent-encode (`%XX`) if the literal byte
1708///     is intended.
1709///
1710/// Returns the parser-shaped reason on rejection (without wrapping in
1711/// any error variant) so each per-axis caller — `validate_entrada_path`
1712/// for `:entrada :paths` entries, `WitContract::target` for the HTTP-
1713/// shaped `:contratos :endpoint` axis, every future per-path lift
1714/// (the M4 CR materializer's per-path validator, the future
1715/// per-`HTTPRouteRule` per-path-match emission) — wraps the same
1716/// reason in its own typed `*Invalid { <axis>, reason }` variant. The
1717/// reason wording is axis-agnostic ("HTTP path matchers reject
1718/// `//`") so every call site reading the same diagnostic points at
1719/// the same rule; drift between any two axes' rule enforcement is a
1720/// build error visible at this predicate, not a per-renderer "this
1721/// passed validate but failed admission" surprise.
1722///
1723/// Empty input is rejected at the call site (each axis has its own
1724/// narrower `*Empty` variant — [`crate::AplicacaoError::EntradaPathEmpty`],
1725/// [`crate::AplicacaoError::ContratoEndpointEmpty`]) before this
1726/// predicate is consulted, mirroring `is_dns_1123_label`'s empty-first
1727/// cascade. The predicate body re-checks empty + leading-`/`
1728/// defensively so it can be called from any future call site without
1729/// a shape-mismatch footgun.
1730///
1731/// Lifted from `caixa-core::aplicacao::validate_entrada_path` (where
1732/// it was first inlined for `:entrada :paths` in 55410e4) at the
1733/// second occurrence of the HTTP-path-grammar — the `:contratos
1734/// :endpoint` axis (c4213a4 gated non-empty + leading-`/` only,
1735/// silently passing the same authoring footguns the `:entrada :paths`
1736/// gate catches) — so the second axis lands as a thin three-line
1737/// wrapper at the per-axis call site rather than re-inlining 90 lines
1738/// of grammar enforcement. Same compounding shape as
1739/// `is_dns_1123_label` (lifted at its third occurrence in 31bfa43)
1740/// and the M2-overlay / label-selector helpers (9e3a057, 9d09cfb,
1741/// 9dbeafd, 31455a7, 07a4544) on the render side — each lifted a
1742/// recurring shape into a typed primitive at the threshold where the
1743/// duplication budget would otherwise have been exceeded.
1744///
1745/// # Errors
1746///
1747/// Returns the parser-shaped reason naming the specific violation
1748/// (length / character-class / segment / consecutive-slash), without
1749/// wrapping in any error variant — every caller maps the same
1750/// `String` into its own typed `*Invalid { <axis>, reason }` enum
1751/// variant.
1752pub fn is_gateway_api_http_path(path: &str) -> Result<(), String> {
1753    if path.is_empty() {
1754        return Err("must not be empty".to_string());
1755    }
1756    if !path.starts_with('/') {
1757        return Err("must start with `/` (HTTP path matchers require a leading `/`)".to_string());
1758    }
1759    if path.len() > GATEWAY_API_HTTP_PATH_MAX_LEN {
1760        return Err(format!(
1761            "exceeds HTTP path max length of {GATEWAY_API_HTTP_PATH_MAX_LEN} bytes \
1762             (got {} bytes; both the K8s Gateway API HTTPPathMatch.value OpenAPI \
1763             schema and the Cilium L7 path matcher reject longer values at \
1764             admission time)",
1765            path.len()
1766        ));
1767    }
1768    for &b in path.as_bytes() {
1769        let reason = if b == b'?' {
1770            Some(
1771                "must not contain `?` (queries are matched separately via HTTPRoute \
1772                 `queryParams`, not in the path; drop the `?…` suffix)"
1773                    .to_string(),
1774            )
1775        } else if b == b'#' {
1776            Some(
1777                "must not contain `#` (fragments are client-side and never reach \
1778                 the gateway; drop the `#…` suffix)"
1779                    .to_string(),
1780            )
1781        } else if b == b' ' || b == b'\t' {
1782            Some(format!(
1783                "must not contain whitespace character {ch:?} (percent-encode as `%20` \
1784                 or use `-`/`_` instead)",
1785                ch = b as char
1786            ))
1787        } else if b < 0x20 || b == 0x7F {
1788            Some(format!(
1789                "must not contain control character 0x{b:02x} (HTTP path characters \
1790                 must be printable ASCII; the K8s Gateway API HTTPPathMatch.value and \
1791                 Cilium L7 path matcher both reject control characters at admission \
1792                 time)"
1793            ))
1794        } else if b >= 0x80 {
1795            Some(format!(
1796                "must not contain non-ASCII byte 0x{b:02x} (RFC 3986 requires \
1797                 percent-encoding `%XX` for characters outside the ASCII unreserved \
1798                 + reserved set)"
1799            ))
1800        } else if matches!(
1801            b,
1802            b'"' | b'<' | b'>' | b'[' | b'\\' | b']' | b'^' | b'`' | b'{' | b'|' | b'}'
1803        ) {
1804            // The eleven printable-ASCII bytes outside the K8s Gateway
1805            // API HTTPPathMatch.value apiserver-side OpenAPI regex
1806            // accepted set. RFC 3986 §3.3 `pchar = unreserved /
1807            // pct-encoded / sub-delims / ":" / "@"` excludes them from
1808            // every path-segment, so the apiserver rejects them at
1809            // admission time on every
1810            // `HTTPRoute.spec.rules[].matches[].path.value` landing site
1811            // (and the Cilium L7 path matcher follows the same grammar).
1812            // Until this gate landed `validate` only refused `?`, `#`,
1813            // whitespace, control characters, and non-ASCII bytes; the
1814            // canonical author-side "I wrote a path-template variable"
1815            // / "I copied an OpenAPI route" footguns silently passed
1816            // (`/api/cart/{id}` — Gateway API uses `:foo` for path
1817            // parameters, not `{foo}`; `/api/cart[0]` — index-bracket
1818            // shape; `/api/<placeholder>` — angle-bracket placeholder;
1819            // `/api\path` — Windows path-separator typo; `/api/^foo` —
1820            // accidental shell-regex character) and the failure surfaced
1821            // at apply time as a Gateway API webhook rejection naming
1822            // the offending byte but not the offending caixa.lisp slot.
1823            // Lifting the rejection to caixa-build time makes the
1824            // canonical Gateway API HTTPPathMatch.value accepted set a
1825            // structural property of every validated `:entrada :paths`
1826            // entry and every typed-HTTP `:contratos :endpoint` payload,
1827            // mirroring the c7d05ec / 55410e4 / 4f0390b trajectory each
1828            // brought the per-axis accepted set to match the apiserver
1829            // accepted set verbatim.
1830            Some(format!(
1831                "must not contain reserved character {ch:?} (RFC 3986 \
1832                 path-segment grammar — and the K8s Gateway API \
1833                 HTTPPathMatch.value apiserver-side OpenAPI regex \
1834                 `^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{{2}})+$` — \
1835                 exclude this byte from the `pchar = unreserved / pct-encoded \
1836                 / sub-delims / \":\" / \"@\"` set; percent-encode as \
1837                 `%{b:02X}` if the literal character is intended)",
1838                ch = b as char
1839            ))
1840        } else {
1841            None
1842        };
1843        if let Some(r) = reason {
1844            return Err(r);
1845        }
1846    }
1847    if path.contains("//") {
1848        return Err(
1849            "must not contain consecutive `/` characters (HTTP path matchers reject \
1850             `//`; collapse to a single `/`)"
1851                .to_string(),
1852        );
1853    }
1854    if path.contains("/./") || path == "/." || path.ends_with("/.") {
1855        return Err(
1856            "must not contain the `.` segment (`/./` or trailing `/.`); it is \
1857             semantically a no-op and HTTP path matchers reject it"
1858                .to_string(),
1859        );
1860    }
1861    if path.contains("/../") || path == "/.." || path.ends_with("/..") {
1862        return Err(
1863            "must not contain the `..` parent-segment (`/../` or trailing `/..`); \
1864             path traversal is rejected by HTTP path matchers"
1865                .to_string(),
1866        );
1867    }
1868    Ok(())
1869}
1870
1871/// Max length, in bytes, of a single typed `:contratos :wit` world
1872/// reference passing the [`is_wit_world_ref`] predicate. 128 bytes —
1873/// roughly 8× the longest real-world WIT reference the caixa-mesh test
1874/// fixtures carry (`wasi:keyvalue/store` = 19 bytes) and the WIT registry
1875/// references its peers under (`wasi:http/proxy@0.2.0` = 21 bytes), so
1876/// the cap exists to reject the paste-from-binary footgun (a multi-line
1877/// blob accidentally landed in the `:wit` slot) rather than to constrain
1878/// legitimate authoring. Lifted as a typed const so a future axis
1879/// reaching for the same bound (the M4 per-edge WIT registry resolver,
1880/// the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
1881/// per-contract WIT validator) reads from one place.
1882pub const WIT_IDENT_MAX_LEN: usize = 128;
1883
1884/// Predicate: assert that `s` is a valid WIT (WebAssembly Component
1885/// Model) world reference — the canonical shape every typed
1886/// `:contratos :wit` value carries. The contract — modeled on the
1887/// [WIT IDL grammar][wit] (`namespace:package(/interface)*(@version)?`)
1888/// restricted to the lowercase subset the pleme-io substrate dispatches
1889/// on:
1890///
1891///   - 1..=[`WIT_IDENT_MAX_LEN`] (128) bytes;
1892///   - no whitespace, no control characters, no non-ASCII bytes;
1893///   - exactly one `:` separator splitting the namespace from the
1894///     package — `wasi:http/proxy`, `nats:pub-sub`, `wasi:keyvalue/store`
1895///     (no `:` = there's no namespace to dispatch on; multiple `:` =
1896///     the package half can't parse);
1897///   - an optional `/`-separated interface suffix (one or more
1898///     segments — the WIT grammar allows `('/' id)+` after the package);
1899///   - an optional `@<version>` suffix (one trailing `@` only; the
1900///     version body is a structurally valid SemVer 2.0.0 version —
1901///     non-empty, restricted to the accepted set `[0-9A-Za-z.\-+]`, AND
1902///     round-trippable through [`semver::Version::parse`]: three-part
1903///     `major.minor.patch` numeric core mandatory (two-part `1.0` and
1904///     four-part `1.0.0.0` reject), no leading zeros in numeric
1905///     identifiers (`01.0.0` rejects), no empty pre-release / build-
1906///     metadata identifiers (`1.0.0-` and `1.0.0-.rc1` reject); the WIT
1907///     IDL binds `simple-version` to SemVer verbatim so every byte-set-
1908///     valid but shape-invalid version body fails the upstream WIT
1909///     parser at consume time);
1910///   - every identifier segment (namespace, package, each interface)
1911///     is a lowercase kebab-case ASCII identifier: `[a-z]([a-z0-9]|-)*`,
1912///     starting with a lowercase letter, no consecutive `-`, no
1913///     trailing `-`.
1914///
1915/// Lowercase-only is deliberate — the substrate's
1916/// [`crate::aplicacao::WitContract::is_http`] / `is_pubsub` / `is_store`
1917/// dispatch keys off the lowercase canonical prefix (`wasi:http/`,
1918/// `nats:`, `wasi:keyvalue/`, `kafka:`, `kv:`, `http:`). An uppercase
1919/// `WASI:HTTP/proxy` is structurally a valid WIT identifier under the
1920/// upstream IDL grammar but silently falls through every `is_*` arm and
1921/// renders as a capability-only L4-only edge — the canonical "I thought
1922/// I had L7 HTTP routing, got L4-only" footgun. Lifting the lowercase
1923/// rule to caixa-build time makes the dispatch reachable-by-construction:
1924/// every validated `:wit` value matches exactly one of the three typed
1925/// dispatch arms (or the explicit capability arm), structurally.
1926///
1927/// Returns the parser-shaped reason on rejection (without wrapping in
1928/// any error variant) so each per-axis caller — `WitContract::target`
1929/// for the `:contratos :wit` axis at validate time, the future M4 CR
1930/// materializer's per-contract WIT validator, the future per-edge WIT
1931/// registry resolver — wraps the same reason in its own typed
1932/// `*Invalid { <axis>, reason }` variant. The reason wording is
1933/// axis-agnostic ("WIT identifiers allow only `[a-z0-9-]`") so every
1934/// call site reading the same diagnostic points at the same rule;
1935/// drift between any two axes' rule enforcement is a build error
1936/// visible at this predicate, not a per-renderer "this passed validate
1937/// but silently demoted to capability-only" surprise.
1938///
1939/// Empty input is rejected here (defensively) and at the call site via
1940/// the narrower [`crate::AplicacaoError::EmptyWit`] variant — the same
1941/// empty-first cascade [`is_dns_1123_label`] and
1942/// [`is_gateway_api_http_path`] carry.
1943///
1944/// Lifted as a typed substrate-side primitive on the same trajectory
1945/// the M2-overlay and label-selector helpers (9e3a057, 9d09cfb, 9dbeafd,
1946/// 31455a7, 07a4544) and the value-shape predicates (`is_dns_1123_label`,
1947/// `is_gateway_api_http_path`) already follow — the typed slot's valid
1948/// set matches its dispatch's accepted set, structurally.
1949///
1950/// [wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md
1951///
1952/// # Errors
1953///
1954/// Returns the parser-shaped reason naming the specific violation
1955/// (length / separator / character-class / kebab-shape / SemVer 2.0.0
1956/// structural invariant), without wrapping in any error variant —
1957/// every caller maps the same `String` into its own typed `*Invalid
1958/// { <axis>, reason }` enum variant.
1959pub fn is_wit_world_ref(s: &str) -> Result<(), String> {
1960    if s.is_empty() {
1961        return Err("must not be empty".to_string());
1962    }
1963    if s.len() > WIT_IDENT_MAX_LEN {
1964        return Err(format!(
1965            "exceeds WIT world-reference max length of {WIT_IDENT_MAX_LEN} bytes \
1966             (got {} bytes; legitimate WIT references rarely exceed ~32 bytes — \
1967             this length suggests a paste-from-binary or multi-line blob landed \
1968             in the `:wit` slot)",
1969            s.len()
1970        ));
1971    }
1972    for &b in s.as_bytes() {
1973        if b.is_ascii_whitespace() {
1974            return Err(format!(
1975                "must not contain whitespace character {ch:?} (WIT world references \
1976                 are single tokens with no whitespace between identifier segments)",
1977                ch = b as char
1978            ));
1979        }
1980        if b < 0x20 || b == 0x7F {
1981            return Err(format!(
1982                "must not contain control character 0x{b:02x} (WIT world references \
1983                 are printable ASCII tokens)"
1984            ));
1985        }
1986        if b >= 0x80 {
1987            return Err(format!(
1988                "must not contain non-ASCII byte 0x{b:02x} (WIT world references \
1989                 are restricted to ASCII identifiers + the `:` / `/` / `@` / `-` \
1990                 separators)"
1991            ));
1992        }
1993    }
1994    // Split off the optional `@<version>` suffix first so the
1995    // namespace/package parse below operates on a clean
1996    // `<ns>:<pkg>(/<iface>)*` head.
1997    let (head, version) = match s.split_once('@') {
1998        Some((h, v)) => (h, Some(v)),
1999        None => (s, None),
2000    };
2001    if let Some(ver) = version {
2002        if ver.is_empty() {
2003            return Err(
2004                "trailing `@` must be followed by a version (e.g. `@0.2.0`); drop \
2005                 the trailing `@` to omit the version pin"
2006                    .to_string(),
2007            );
2008        }
2009        if ver.contains('@') {
2010            return Err(
2011                "must contain at most one `@` separator (the optional version suffix \
2012                 is `@<version>`, not `@<ver>@<ver>`)"
2013                    .to_string(),
2014            );
2015        }
2016        if ver.contains(':') || ver.contains('/') {
2017            return Err(format!(
2018                "version suffix {ver:?} must not contain `:` or `/` (those separators \
2019                 are reserved for the namespace and interface axes; the version body \
2020                 is opaque)"
2021            ));
2022        }
2023        // Byte-set gate on the `@<version>` body: SemVer 2.0.0 restricts
2024        // every legal version to the accepted set
2025        // `[0-9A-Za-z.\-+]` — the digit + letter alphabet for the
2026        // `major.minor.patch` numeric core, the `.` segment separator,
2027        // and the `-` / `+` sigils that introduce the optional
2028        // pre-release and build-metadata suffixes. The WIT IDL binds
2029        // `simple-version` to SemVer verbatim (WebAssembly Component
2030        // Model design doc `WIT.md#versions` — `version` is parsed
2031        // through the `semver` crate), so any printable-ASCII byte
2032        // outside that set is guaranteed to fail the upstream WIT
2033        // parser at consume time. Until this gate landed the outer
2034        // whitespace / control / non-ASCII loop above rejected the
2035        // whitespace + control + non-ASCII slices of the byte axis
2036        // and the narrower `contains('@')` / `contains(':' | '/')`
2037        // arms above closed the WIT-reserved separator bytes, but
2038        // every other printable-ASCII byte (`?`, `#`, `!`, `$`, `%`,
2039        // `&`, `'`, `"`, `(`, `)`, `*`, `,`, `;`, `<`, `=`, `>`, `[`,
2040        // `\`, `]`, `^`, `` ` ``, `{`, `|`, `}`, `~`) silently rode
2041        // through — the canonical author-side footguns
2042        // (`wasi:http/proxy@0.2.0?rc1` — URL-query-separator paste
2043        // where the author copied a versioned link and the trailing
2044        // `?ref=…` came along; `wasi:http/proxy@0.2.0#build` —
2045        // URL-fragment paste; `wasi:http/proxy@0.2.0 alpha` — the
2046        // outer whitespace loop already catches this, but before that
2047        // loop landed the space rode through too; `wasi:http/proxy@
2048        // 0.2.0!alpha` — accidental history-expansion `!`;
2049        // `wasi:http/proxy@0.2.0(rc1)` — parenthetical annotation
2050        // from a doc comment) all passed `validate` and failed at
2051        // WIT-parse time far from the source caixa.lisp with a
2052        // parser diagnostic that names the offending byte but not
2053        // the offending `:contratos :wit` slot. Lifting the rejection
2054        // to caixa-build time closes the byte-set axis structurally
2055        // — every validated `@<version>` body matches the SemVer
2056        // 2.0.0 accepted set, and drift between the typed slot's
2057        // accepted set and the upstream WIT parser's accepted set is
2058        // impossible-by-construction.
2059        //
2060        // Same top-and-bottom-edge discipline the peer axes carry —
2061        // [`is_gateway_api_http_path`]'s eleven-byte RFC-3986-reserved
2062        // rejection set for `:entrada :paths` / `:contratos :endpoint`,
2063        // [`is_nats_subject`]'s strict `[A-Za-z0-9_-]` per-token
2064        // character set for `:contratos :subject`,
2065        // [`is_wit_kebab_id`]'s lowercase-kebab enforcement for the
2066        // WIT namespace/package/interface segments — the typed slot's
2067        // valid set matches the downstream parser's accepted set,
2068        // structurally.
2069        for &b in ver.as_bytes() {
2070            let valid = b.is_ascii_alphanumeric() || b == b'.' || b == b'-' || b == b'+';
2071            if !valid {
2072                return Err(format!(
2073                    "version suffix {ver:?} contains invalid character {ch:?} \
2074                     (SemVer 2.0.0 restricts the `@<version>` body to the accepted \
2075                     set `[0-9A-Za-z.\\-+]` — digits + letters for the \
2076                     `major.minor.patch` numeric core, `.` for segment separators, \
2077                     `-` for the pre-release suffix, `+` for the build-metadata \
2078                     suffix; every other byte fails the upstream WIT parser at \
2079                     consume time)",
2080                    ch = b as char
2081                ));
2082            }
2083        }
2084        // Structural SemVer 2.0.0 parse on the `@<version>` body: every
2085        // byte-set-valid version body (`[0-9A-Za-z.\-+]`, the accepted-
2086        // set arm above) is not necessarily a *structurally* valid
2087        // SemVer version. SemVer 2.0.0 imposes shape rules on top of the
2088        // byte set — three-part `major.minor.patch` mandatory (two-part
2089        // `1.0` and four-part `1.0.0.0` reject), no leading zeros in
2090        // numeric identifiers (`01.0.0` rejects, `10.0.0` accepts,
2091        // `1.0.0-01` rejects while `1.0.0-alpha01` accepts because the
2092        // pre-release identifier is alphanumeric not numeric), no empty
2093        // identifiers (`1.0.0-` and `1.0.0+` reject; `1.0.0-.rc1` and
2094        // `1.0.0-alpha..beta` reject; `1.0.0+.abc` and
2095        // `1.0.0+build..42` reject). Until this gate landed the byte-set
2096        // arm above closed only the per-byte accepted set, and every
2097        // *shape*-invalid version body — the canonical author-side
2098        // paste footguns (`wasi:http/proxy@1.0` two-part-numeric-core
2099        // paste from a Node.js `"engines"` field, `wasi:http/proxy@1`
2100        // one-part paste from a Docker `:v1` tag, `wasi:http/proxy@v0.2.0`
2101        // `v`-prefixed git-tag paste that strayed into the version body,
2102        // `wasi:http/proxy@01.0.0` mistaken zero-padded major from a
2103        // date-based version scheme, `wasi:http/proxy@1.0.0.0` four-part
2104        // paste from a Microsoft / Java build-number convention,
2105        // `wasi:http/proxy@1.0.0-` half-typed pre-release the author
2106        // started and left dangling, `wasi:http/proxy@1.0.0+` peer for
2107        // build-metadata) rode through the byte-set gate and failed at
2108        // WIT-parse time (the WIT IDL's `simple-version` binds through
2109        // the `semver` crate at consume time — see WebAssembly Component
2110        // Model design doc `WIT.md#versions`, and both the M4
2111        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-
2112        // contract WIT validator (MESH-COMPOSITION §III.2 #5) and the
2113        // future per-edge WIT registry resolver strict-parse the
2114        // `@<version>` body through the same crate). Failure surfaced
2115        // far from the source `caixa.lisp` with a bare `semver::Error`
2116        // that names the specific structural violation but not the
2117        // offending `:contratos :wit` slot. Lifting the parse to caixa-
2118        // build time closes the structural axis: every validated
2119        // `@<version>` body past this call is byte-for-byte round-
2120        // trippable through [`semver::Version::parse`] without re-
2121        // checking at any downstream WIT-consumer layer.
2122        //
2123        // Thin wrapper around [`semver::Version::parse`] — the same
2124        // parser [`crate::Caixa::validate_versao`] (the peer top-level
2125        // `:versao` axis) and [`crate::CaixaVersion::parse`] consume,
2126        // so the accepted set is structurally identical across every
2127        // `:versao`-shaped axis the substrate carries. Maps the
2128        // `semver::Error` reason verbatim into a self-locating
2129        // diagnostic naming the offending version body + the SemVer
2130        // 2.0.0 canonical shape the author intended, so the failure
2131        // is grep-locatable in the `caixa.lisp` (search for
2132        // `:wit "…@<value>"`) and fixable in one edit. Same top-and-
2133        // bottom-edge discipline the peer typed-codec axes carry —
2134        // every typed slot whose accepted set the substrate reads is
2135        // strict-parsed against the downstream consumer's canonical
2136        // parser at build time, not at apply time.
2137        if let Err(e) = semver::Version::parse(ver) {
2138            return Err(format!(
2139                "version suffix {ver:?} is not a structurally valid SemVer 2.0.0 \
2140                 version: {e} (the WIT IDL binds `@<version>` to SemVer 2.0.0 \
2141                 verbatim — three-part `major.minor.patch` numeric core, no \
2142                 leading zeros in numeric identifiers, no empty pre-release / \
2143                 build-metadata identifiers; every other shape fails the \
2144                 upstream WIT parser at consume time)"
2145            ));
2146        }
2147    }
2148    // Then split the head on `:` — exactly one separator, splitting the
2149    // namespace from the package(/interface) body.
2150    let Some((ns, rest)) = head.split_once(':') else {
2151        return Err(format!(
2152            "must contain a `:` separating the namespace from the package (e.g. \
2153             `wasi:http/proxy`); got {s:?} with no `:` — pleme-io dispatches `:wit` \
2154             values on the canonical `<namespace>:<package>` shape and silently \
2155             demotes unmatched shapes to a capability-only L4 edge"
2156        ));
2157    };
2158    if rest.contains(':') {
2159        return Err(format!(
2160            "must contain exactly one `:` separator (between namespace and package); \
2161             got {s:?} with multiple `:`"
2162        ));
2163    }
2164    is_wit_kebab_id(ns)
2165        .map_err(|r| format!("namespace {ns:?} is not a valid WIT identifier: {r}"))?;
2166    let mut segments = rest.split('/');
2167    let pkg = segments.next().unwrap_or("");
2168    is_wit_kebab_id(pkg)
2169        .map_err(|r| format!("package {pkg:?} is not a valid WIT identifier: {r}"))?;
2170    for iface in segments {
2171        is_wit_kebab_id(iface)
2172            .map_err(|r| format!("interface {iface:?} is not a valid WIT identifier: {r}"))?;
2173    }
2174    Ok(())
2175}
2176
2177/// Predicate: assert that `s` is a lowercase kebab-case ASCII identifier
2178/// — the WIT IDL `id ::= word ('-' word)*` rule restricted to the
2179/// lowercase `word ::= [a-z][a-z0-9]*` arm the pleme-io substrate
2180/// dispatches on. Private because every legitimate caller flows through
2181/// [`is_wit_world_ref`] (which segments the world reference and runs
2182/// this predicate per segment); exposing it directly would invite
2183/// per-axis WIT-shape gates that re-implement the segmenting logic
2184/// inline.
2185fn is_wit_kebab_id(s: &str) -> Result<(), String> {
2186    if s.is_empty() {
2187        return Err("must not be empty".to_string());
2188    }
2189    let bytes = s.as_bytes();
2190    if !bytes[0].is_ascii_lowercase() {
2191        let msg = if bytes[0].is_ascii_uppercase() {
2192            format!(
2193                "must start with a lowercase ASCII letter (got uppercase {ch:?}); \
2194                 pleme-io dispatches `:wit` values on the lowercase canonical shape \
2195                 — `wasi:http/proxy` is recognized, `WASI:HTTP/proxy` is silently \
2196                 demoted to a capability-only edge",
2197                ch = bytes[0] as char
2198            )
2199        } else if bytes[0].is_ascii_digit() {
2200            format!(
2201                "must start with a lowercase ASCII letter (got digit {ch:?}); WIT \
2202                 identifiers begin with a letter, not a digit",
2203                ch = bytes[0] as char
2204            )
2205        } else if bytes[0] == b'-' {
2206            "must not start with `-` (WIT identifiers are kebab-case words; the \
2207             leading character is a lowercase letter)"
2208                .to_string()
2209        } else {
2210            format!(
2211                "must start with a lowercase ASCII letter (got {ch:?}); WIT \
2212                 identifiers allow only `[a-z0-9-]`",
2213                ch = bytes[0] as char
2214            )
2215        };
2216        return Err(msg);
2217    }
2218    if bytes[bytes.len() - 1] == b'-' {
2219        return Err(
2220            "must not end with `-` (WIT identifiers are kebab-case words separated \
2221             by single hyphens; no trailing `-`)"
2222                .to_string(),
2223        );
2224    }
2225    let mut prev_hyphen = false;
2226    for &b in bytes {
2227        if b == b'-' {
2228            if prev_hyphen {
2229                return Err(
2230                    "must not contain consecutive `-` characters (WIT identifiers \
2231                     join words with single hyphens, not `--`)"
2232                        .to_string(),
2233                );
2234            }
2235            prev_hyphen = true;
2236            continue;
2237        }
2238        let after_hyphen = prev_hyphen;
2239        prev_hyphen = false;
2240        if b.is_ascii_uppercase() {
2241            return Err(format!(
2242                "must be lowercase (got uppercase character {ch:?}); pleme-io \
2243                 dispatches `:wit` values on the lowercase canonical shape — \
2244                 `wasi:http/proxy` is recognized, `WASI:HTTP/proxy` is silently \
2245                 demoted to a capability-only edge",
2246                ch = b as char
2247            ));
2248        }
2249        // Per-word first-byte gate. The doc-comment above binds this
2250        // predicate to the WIT IDL rule `id ::= word ('-' word)*` with
2251        // `word ::= [a-z][a-z0-9]*` — each hyphen-separated word must
2252        // begin with a lowercase letter, not a digit. The full-id
2253        // first-byte arm above ([`is_wit_kebab_id`] line ~974) closes
2254        // the leading-digit / leading-hyphen / leading-uppercase footguns
2255        // for the *first* word (`"1http"`, `"-http"`, `"Http"`); this
2256        // arm closes the same "word must begin with a lowercase letter"
2257        // rule for *every subsequent* word after a `-` separator. Until
2258        // this gate landed the byte-set arm below accepted `[a-z0-9-]`
2259        // uniformly across all positions, so an identifier like
2260        // `"pub-1sub"` / `"proxy-2beta"` / `"cap-9"` passed the byte-set
2261        // gate (every byte lies in `[a-z0-9-]`), passed the leading-`-`
2262        // arm (the first byte is `p`/`c`, not `-`), passed the
2263        // consecutive-`-` arm (no `--`), passed the trailing-`-` arm
2264        // (last byte is a lowercase letter or digit, not `-`), and was
2265        // silently accepted — the canonical `abc-<digit>*` word-shape
2266        // footgun where an author's paste-from-versioned-slug (`"proxy-2"`
2267        // from a `v2`-tagged interface hand-transcribed) or a
2268        // programmatic string-interpolation (`format!("{stem}-{n}")` with
2269        // a numeric `n`) landed in the `:contratos :wit` slot's segment.
2270        // The upstream WIT parser (WebAssembly/component-model spec §WIT
2271        // grammar; `wit-parser` crate's `id!` production) then failed at
2272        // WIT-parse time far from the source caixa.lisp with a parser
2273        // diagnostic that names the offending byte but not the offending
2274        // `:contratos :wit` slot, and the typed slot's accepted set drifted
2275        // from the upstream parser's accepted set on the exact class the
2276        // doc-comment above already documented as rejected — a
2277        // documentation-vs-implementation drift, not a novel rule. Lifting
2278        // the rejection to caixa-build time closes the per-word-first-byte
2279        // axis structurally — every validated WIT identifier past this
2280        // predicate matches the WIT IDL word grammar per-word, not just at
2281        // the first byte, and drift between the typed slot's accepted set
2282        // and the upstream WIT parser's accepted set is impossible-by-
2283        // construction on the digit-after-hyphen axis (the last remaining
2284        // documented-but-unenforced arm on the WIT kebab predicate).
2285        //
2286        // Same top-and-bottom-edge discipline the peer axes carry: every
2287        // caller ([`is_wit_world_ref`] on the `:contratos :wit` axis, and
2288        // through it the M3 `WitContract::target` cross-check at
2289        // [`crate::AplicacaoSpec::validate`]) now refuses the canonical
2290        // author-side "word two starts with a version-shape digit paste"
2291        // footgun at validate time rather than at wit-parser consume
2292        // time. Same trajectory as bb4e6c4 (`is_wit_world_ref` byte-set
2293        // gate on the `@<version>` suffix) and 9f7b894 (`is_wit_world_ref`
2294        // structural SemVer 2.0.0 parse on the `@<version>` suffix) on
2295        // the peer per-suffix axes — the same "typed-slot's accepted set
2296        // matches the downstream parser's accepted set, structurally"
2297        // discipline extended here from the version-body axis to the
2298        // per-word first-byte axis of the identifier body itself.
2299        if after_hyphen && b.is_ascii_digit() {
2300            return Err(format!(
2301                "word after `-` starts with digit {ch:?} (WIT identifiers are \
2302                 `id ::= word ('-' word)*` with `word ::= [a-z][a-z0-9]*` — every \
2303                 word begins with a lowercase letter, not a digit; the upstream WIT \
2304                 parser rejects an identifier of this shape at consume time. Insert \
2305                 a lowercase-letter prefix on the offending word — `pub-v1sub` \
2306                 instead of `pub-1sub`, `proxy-v2beta` instead of `proxy-2beta`)",
2307                ch = b as char
2308            ));
2309        }
2310        if !(b.is_ascii_lowercase() || b.is_ascii_digit()) {
2311            let msg = if b == b'_' {
2312                "contains `_` (WIT identifiers are kebab-case; use `-` between \
2313                 words instead of `_`)"
2314                    .to_string()
2315            } else if b == b'.' {
2316                "contains `.` (WIT identifiers are single kebab-case words; split \
2317                 into separate namespace/package/interface segments via `:` and \
2318                 `/` instead of `.`)"
2319                    .to_string()
2320            } else {
2321                format!(
2322                    "contains invalid character {ch:?} (WIT identifiers allow only \
2323                     `[a-z0-9-]`)",
2324                    ch = b as char
2325                )
2326            };
2327            return Err(msg);
2328        }
2329    }
2330    Ok(())
2331}
2332
2333/// Max length, in bytes, of a single typed `:contratos :subject` NATS
2334/// subject passing the [`is_nats_subject`] predicate. 256 bytes —
2335/// matches the upstream NATS Java client's `MAX_SUBJECT_LENGTH`
2336/// constant and sits well above the longest legitimate subject the
2337/// caixa-mesh test fixtures + example checkout-aplicacao carry
2338/// (`"checkout.events.charge.failed"` = 30 bytes, `"rio.events.order.charged"`
2339/// = 25 bytes). The cap exists to reject the paste-from-binary footgun
2340/// (a multi-line blob accidentally landed in the `:subject` slot)
2341/// rather than to constrain legitimate authoring. Lifted as a typed
2342/// const so a future axis reaching for the same bound (the M4
2343/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-subject
2344/// validator, the future NATS Stream/Consumer CR emitter for the
2345/// `nats:pub-sub` branch of `:contratos`, the future per-edge
2346/// `:politicas`-derived NATS-aware policy overlay) reads from one
2347/// place.
2348pub const NATS_SUBJECT_MAX_LEN: usize = 256;
2349
2350/// Predicate: assert that `s` is a valid NATS subject — the canonical
2351/// shape every typed `:contratos :subject` value carries. The
2352/// contract — modeled on the [NATS subject grammar][nats] (dot-
2353/// separated tokens with `*` / `>` wildcards), restricted to the
2354/// strict `[A-Za-z0-9_-]` per-token character set the NATS server's
2355/// subject parser accepts at runtime:
2356///
2357///   - 1..=[`NATS_SUBJECT_MAX_LEN`] (256) bytes;
2358///   - no whitespace, no control characters, no non-ASCII bytes
2359///     (RFC 3986 requires `%XX` percent-encoding for non-ASCII; NATS
2360///     subjects predate that and reject any byte outside the strict
2361///     ASCII identifier set);
2362///   - one-or-more `.`-separated tokens — no leading `.`, no trailing
2363///     `.`, no consecutive `.` (NATS rejects empty tokens between
2364///     separators);
2365///   - each token is one of:
2366///     - a concrete identifier `[A-Za-z0-9_-]+` (NATS subjects are
2367///       case-sensitive; unlike DNS-1123 we don't lowercase-fold,
2368///       and underscores are permitted since NATS itself accepts them
2369///       in tokens);
2370///     - the `*` single-token wildcard (matches exactly one token;
2371///       allowed at any segment position);
2372///     - the `>` multi-token wildcard (matches one-or-more trailing
2373///       tokens; allowed ONLY as the final segment — `foo.>` matches
2374///       `foo.bar` / `foo.bar.baz`, `foo.>.bar` is rejected outright).
2375///
2376/// Returns the parser-shaped reason on rejection (without wrapping in
2377/// any error variant) so each per-axis caller — `WitContract::target`
2378/// for the `:contratos :subject` axis at validate time, the future M4
2379/// CR materializer's per-subject validator, the future NATS Stream/
2380/// Consumer CR emitter — wraps the same reason in its own typed
2381/// `*Invalid { <axis>, reason }` variant. The reason wording is axis-
2382/// agnostic ("NATS subjects reject empty tokens between separators")
2383/// so every call site reading the same diagnostic points at the same
2384/// rule; drift between any two axes' rule enforcement is a build
2385/// error visible at this predicate, not a per-renderer "this passed
2386/// validate but the NATS server rejected at publish/subscribe" surprise.
2387///
2388/// Empty input is rejected here (defensively) and at the call site via
2389/// the narrower [`crate::AplicacaoError::ContratoSubjectEmpty`] variant
2390/// — the same empty-first cascade [`is_dns_1123_label`],
2391/// [`is_gateway_api_http_path`], and [`is_wit_world_ref`] carry.
2392///
2393/// Lifted as a typed substrate-side primitive on the same trajectory
2394/// the M2-overlay and label-selector helpers (9e3a057, 9d09cfb,
2395/// 9dbeafd, 31455a7, 07a4544) and the value-shape predicates
2396/// (`is_dns_1123_label`, `is_gateway_api_http_path`,
2397/// `is_wit_world_ref`) already follow — the typed slot's valid set
2398/// matches the NATS server's accepted set, structurally.
2399///
2400/// [nats]: https://docs.nats.io/nats-concepts/subjects
2401///
2402/// # Errors
2403///
2404/// Returns the parser-shaped reason naming the specific violation
2405/// (length / separator / character-class / wildcard-position), without
2406/// wrapping in any error variant — every caller maps the same
2407/// `String` into its own typed `*Invalid { <axis>, reason }` enum
2408/// variant.
2409pub fn is_nats_subject(s: &str) -> Result<(), String> {
2410    if s.is_empty() {
2411        return Err("must not be empty".to_string());
2412    }
2413    if s.len() > NATS_SUBJECT_MAX_LEN {
2414        return Err(format!(
2415            "exceeds NATS subject max length of {NATS_SUBJECT_MAX_LEN} bytes \
2416             (got {} bytes; legitimate NATS subjects rarely exceed ~64 bytes — \
2417             this length suggests a paste-from-binary or multi-line blob landed \
2418             in the `:subject` slot)",
2419            s.len()
2420        ));
2421    }
2422    for &b in s.as_bytes() {
2423        if b == b' ' || b == b'\t' {
2424            return Err(format!(
2425                "must not contain whitespace character {ch:?} (NATS subjects \
2426                 are single tokens with no whitespace between dot-separated \
2427                 segments)",
2428                ch = b as char
2429            ));
2430        }
2431        if b < 0x20 || b == 0x7F {
2432            return Err(format!(
2433                "must not contain control character 0x{b:02x} (NATS subjects \
2434                 are printable ASCII tokens; the NATS server's subject parser \
2435                 rejects control characters at publish/subscribe time)"
2436            ));
2437        }
2438        if b >= 0x80 {
2439            return Err(format!(
2440                "must not contain non-ASCII byte 0x{b:02x} (NATS subjects \
2441                 are restricted to `[A-Za-z0-9_-]` per token + the `.` \
2442                 separator and the `*` / `>` wildcards)"
2443            ));
2444        }
2445    }
2446    if s.starts_with('.') {
2447        return Err(
2448            "must not start with `.` (NATS subjects reject empty leading \
2449             tokens; drop the leading `.` separator)"
2450                .to_string(),
2451        );
2452    }
2453    if s.ends_with('.') {
2454        return Err(
2455            "must not end with `.` (NATS subjects reject empty trailing \
2456             tokens; use the `>` multi-token wildcard to match arbitrary \
2457             trailing segments instead)"
2458                .to_string(),
2459        );
2460    }
2461    if s.contains("..") {
2462        return Err(
2463            "must not contain consecutive `.` characters (NATS subjects \
2464             reject empty tokens between separators; use the `*` single-\
2465             token wildcard to match any one token)"
2466                .to_string(),
2467        );
2468    }
2469    let segments: Vec<&str> = s.split('.').collect();
2470    let last_idx = segments.len() - 1;
2471    for (i, seg) in segments.iter().enumerate() {
2472        is_nats_subject_segment(seg, i, last_idx)?;
2473    }
2474    Ok(())
2475}
2476
2477/// Predicate: assert that `seg` is a valid NATS subject token at index
2478/// `i` of a `total = last_idx + 1`-segment subject. Private because
2479/// every legitimate caller flows through [`is_nats_subject`] (which
2480/// splits the subject on `.` and runs this predicate per segment);
2481/// exposing it directly would invite per-axis NATS-segment gates that
2482/// re-implement the splitting logic inline.
2483///
2484/// Mirrors the [`is_wit_kebab_id`] / [`is_wit_world_ref`] private-helper
2485/// pair on the WIT predicate.
2486fn is_nats_subject_segment(seg: &str, i: usize, last_idx: usize) -> Result<(), String> {
2487    if seg == "*" {
2488        return Ok(());
2489    }
2490    if seg == ">" {
2491        if i != last_idx {
2492            return Err(format!(
2493                "the `>` multi-token wildcard is only allowed as the \
2494                 final segment (got `>` at segment {one_based} of {total}; \
2495                 move to the end or use `*` for a single-token wildcard)",
2496                one_based = i + 1,
2497                total = last_idx + 1
2498            ));
2499        }
2500        return Ok(());
2501    }
2502    for &b in seg.as_bytes() {
2503        let valid = b.is_ascii_alphanumeric() || b == b'_' || b == b'-';
2504        if !valid {
2505            let msg = if b == b'*' {
2506                "contains `*` mid-segment (NATS wildcards are standalone \
2507                 tokens — `foo.*.bar` matches one middle token, `foo*` \
2508                 does not; split into separate `.`-separated segments)"
2509                    .to_string()
2510            } else if b == b'>' {
2511                "contains `>` mid-segment (NATS wildcards are standalone \
2512                 tokens — `foo.>` matches all trailing tokens, `foo>` \
2513                 does not; split into separate `.`-separated segments)"
2514                    .to_string()
2515            } else {
2516                format!(
2517                    "contains invalid character {ch:?} in subject segment \
2518                     (NATS subject tokens allow only `[A-Za-z0-9_-]`; use \
2519                     `_` or `-` instead)",
2520                    ch = b as char
2521                )
2522            };
2523            return Err(msg);
2524        }
2525    }
2526    Ok(())
2527}
2528
2529/// Max length, in bytes, of a single typed `:contratos :slot` WASI
2530/// keyvalue store key/template passing the [`is_wasi_keyvalue_slot`]
2531/// predicate. 512 bytes — generously above the longest realistic slot
2532/// template (`"checkout/$orderId"` = 17 bytes, `"users:{tenant}/{id}"`
2533/// = 19 bytes, `"session.tokens.<sid>"` = 20 bytes) and well under any
2534/// canonical WASI-keyvalue backend's per-key limit (etcd: 1.5 MB,
2535/// DynamoDB partition+sort key: 2 KB combined, Redis: 512 MB — the cap
2536/// is chosen for the *template* slot a typed `:contratos` edge
2537/// authors, not the realized key at runtime). The cap exists to reject
2538/// the paste-from-binary footgun (a multi-line blob accidentally landed
2539/// in the `:slot` slot) rather than to constrain legitimate authoring.
2540/// Lifted as a typed const so a future axis reaching for the same
2541/// bound (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
2542/// per-slot validator, the future per-Servico `:capabilities`
2543/// `wasi:keyvalue/store` axis's per-slot validator when M4 lands
2544/// per-capability typed slots, the future per-edge `:politicas`-derived
2545/// kv-backend-aware policy overlay's per-slot validator) reads from
2546/// one place. Same lift trajectory as [`NATS_SUBJECT_MAX_LEN`] (which
2547/// caps the peer pub-sub payload axis at 256 bytes — twice that here
2548/// because kv slot templates legitimately compose more `/`-separated
2549/// path segments + template variables than NATS subjects do
2550/// `.`-separated tokens).
2551pub const WASI_KV_SLOT_MAX_LEN: usize = 512;
2552
2553/// Predicate: assert that `s` is a valid WASI keyvalue store slot
2554/// template — the canonical shape every typed `:contratos :slot` value
2555/// carries when its `:wit` dispatch resolves to the
2556/// [`WitTarget::Store`][st] arm (`wasi:keyvalue/store`, `kv:*`). The
2557/// WASI keyvalue 0.2 specification ([`bucket = string`, `key = string`,
2558/// both opaque][wasi-kv]) places no syntactic constraints on the key
2559/// shape, so the substrate enforces the canonical printable-ASCII
2560/// floor every realistic kv backend admits: no raw whitespace, no
2561/// control bytes, no non-ASCII bytes, length-bounded by
2562/// [`WASI_KV_SLOT_MAX_LEN`]. The grammar:
2563///
2564///   - 1..=[`WASI_KV_SLOT_MAX_LEN`] (512) bytes;
2565///   - no whitespace (space, tab — kv slot templates are single-token
2566///     identifiers / path expressions, whitespace is the canonical
2567///     paste-from-doc footgun whose runtime behavior varies
2568///     unpredictably across backends — etcd accepts, Redis accepts
2569///     but rejects subsequent CLI ops, DynamoDB rejects on write);
2570///   - no ASCII control characters (`0x00..0x1F`, `0x7F`) — every
2571///     kv backend either rejects on write (DynamoDB, etcd) or admits
2572///     and silently breaks at the next read (Redis: `\r\n` corrupts
2573///     the RESP protocol framing if the slot template is rendered
2574///     directly into a key without re-encoding);
2575///   - no non-ASCII bytes (`>= 0x80`) — RFC 3986-style percent-
2576///     encoding (`%XX`) is the substrate's canonical UTF-8 escape
2577///     for kv slot templates the author wants to namespace by
2578///     non-ASCII identifier; raw non-ASCII silently differs between
2579///     backends (etcd preserves bytes verbatim; Redis-via-RESP3 may
2580///     re-encode; DynamoDB rejects).
2581///
2582/// The predicate is intentionally permissive on structure: all
2583/// printable ASCII bytes (`0x21..0x7E`) are admitted, including
2584/// `/` (path separators), `:` (namespace separators), `.`
2585/// (dot-namespacing), `-`/`_` (identifier separators), `$`/`{`/`}`/`<`/`>`
2586/// (template-variable syntaxes — the canonical `"checkout/$orderId"`
2587/// shape carries `$`-prefixed identifiers, alternate `"users:{id}"` /
2588/// `"session.<sid>"` shapes carry `{}` / `<>` brackets), and the
2589/// remaining ASCII punctuation. The substrate doesn't know which kv
2590/// backend the runtime resolves [`WitTarget::Store`][st] to — that
2591/// choice is per-cluster, made by the operator's kv-provider binding
2592/// — so the typed slot enforces the intersection-floor every backend
2593/// admits rather than any one backend's stricter superset.
2594///
2595/// Returns the parser-shaped reason on rejection (without wrapping in
2596/// any error variant) so each per-axis caller — [`WitContract::target`]
2597/// for the `:contratos :slot` axis at validate time, the future M4 CR
2598/// materializer's per-slot validator, the future per-Servico
2599/// `:capabilities wasi:keyvalue/store` per-slot validator — wraps the
2600/// same reason in its own typed `*Invalid { <axis>, reason }` variant.
2601/// The reason wording is axis-agnostic ("kv slot templates reject raw
2602/// whitespace") so every call site reading the same diagnostic points
2603/// at the same rule; drift between any two axes' rule enforcement is
2604/// a build error visible at this predicate, not a per-renderer "this
2605/// passed validate but the kv backend rejected on first write"
2606/// surprise.
2607///
2608/// Empty input is rejected here (defensively) and at the call site
2609/// via the narrower [`crate::AplicacaoError::ContratoSlotEmpty`]
2610/// variant — the same empty-first cascade [`is_dns_1123_label`],
2611/// [`is_gateway_api_http_path`], [`is_wit_world_ref`], and
2612/// [`is_nats_subject`] all carry.
2613///
2614/// Lifted as a typed substrate-side primitive on the same trajectory
2615/// the peer payload-axis predicates ([`is_gateway_api_http_path`] for
2616/// `:endpoint`, [`is_nats_subject`] for `:subject`) already follow —
2617/// the typed slot's valid set matches the kv backend intersection-
2618/// floor's accepted set, structurally. The fifth value-shape primitive
2619/// to land in [`crate::render`] after [`is_dns_1123_label`],
2620/// [`is_gateway_api_http_path`], [`is_wit_world_ref`], and
2621/// [`is_nats_subject`] — and the one that closes the trajectory across
2622/// every typed payload axis the [`WitContract::target`] dispatch
2623/// carries (HTTP `:endpoint`, PubSub `:subject`, Store `:slot`).
2624///
2625/// [st]: crate::WitTarget::Store
2626/// [wasi-kv]: https://github.com/WebAssembly/wasi-keyvalue
2627///
2628/// # Errors
2629///
2630/// Returns the parser-shaped reason naming the specific violation
2631/// (length / whitespace / control / non-ASCII), without wrapping in
2632/// any error variant — every caller maps the same `String` into its
2633/// own typed `*Invalid { <axis>, reason }` enum variant.
2634pub fn is_wasi_keyvalue_slot(s: &str) -> Result<(), String> {
2635    if s.is_empty() {
2636        return Err("must not be empty".to_string());
2637    }
2638    if s.len() > WASI_KV_SLOT_MAX_LEN {
2639        return Err(format!(
2640            "exceeds WASI keyvalue slot max length of {WASI_KV_SLOT_MAX_LEN} bytes \
2641             (got {} bytes; legitimate kv slot templates rarely exceed ~64 bytes — \
2642             this length suggests a paste-from-binary or multi-line blob landed in \
2643             the `:slot` slot)",
2644            s.len()
2645        ));
2646    }
2647    for &b in s.as_bytes() {
2648        if b == b' ' || b == b'\t' {
2649            return Err(format!(
2650                "must not contain whitespace character {ch:?} (kv slot templates \
2651                 are single-token identifiers / path expressions; raw whitespace \
2652                 behaves unpredictably across kv backends — percent-encode as `%20` \
2653                 or use `-`/`_` to namespace)",
2654                ch = b as char
2655            ));
2656        }
2657        if b < 0x20 || b == 0x7F {
2658            return Err(format!(
2659                "must not contain control character 0x{b:02x} (kv slot templates \
2660                 are printable ASCII; control bytes either get rejected on write \
2661                 by strict backends — DynamoDB, etcd — or silently corrupt the \
2662                 next read on permissive ones — Redis RESP framing)"
2663            ));
2664        }
2665        if b >= 0x80 {
2666            return Err(format!(
2667                "must not contain non-ASCII byte 0x{b:02x} (RFC 3986 requires \
2668                 percent-encoding `%XX` for characters outside the ASCII unreserved \
2669                 + reserved set; raw non-ASCII bytes are admitted by some kv backends \
2670                 verbatim and re-encoded by others — the typed slot's value set is \
2671                 the intersection-floor every backend admits identically)"
2672            ));
2673        }
2674    }
2675    Ok(())
2676}
2677
2678/// Max length, in bytes, of a single typed git ref name passing the
2679/// [`is_git_ref_name`] predicate. 255 bytes — matches the POSIX
2680/// `NAME_MAX` filesystem-component limit every Git porcelain ultimately
2681/// stores refs into (loose `refs/<category>/<name>` files under
2682/// `.git/refs/`, packed-refs index entries). Refs that exceed this cap
2683/// fail to land on disk at clone/fetch time on every realistic
2684/// filesystem (ext4, btrfs, xfs, APFS, NTFS), so a `:tag` / `:branch`
2685/// past that length is unsourceable in practice. The cap exists to
2686/// reject the paste-from-binary footgun (a multi-line blob accidentally
2687/// landed in the `:tag` slot) rather than to constrain legitimate
2688/// authoring — realistic tag/branch names rarely exceed ~32 bytes
2689/// (`"v0.1.0"` = 6 bytes, `"release-1.0-alpha.1"` = 19 bytes,
2690/// `"feature/checkout-rewrite"` = 24 bytes). Lifted as a typed const
2691/// so a future axis reaching for the same bound (the future
2692/// `lacre.lisp` ref-shape gate on resolved-pin axes, the future M4
2693/// per-dep CR materializer's per-pin validator) reads from one place.
2694pub const GIT_REF_NAME_MAX_LEN: usize = 255;
2695
2696/// Predicate: assert that `s` is a valid Git ref name under the
2697/// `git check-ref-format --allow-onelevel` rule set — the canonical
2698/// shape every typed `:fonte (:tipo git …)` `:tag` / `:branch` value
2699/// carries. The contract — modeled on the [`git check-ref-format`][gcr]
2700/// grammar the Git porcelain enforces at clone/fetch/checkout time,
2701/// with the multi-component requirement waived (`:tag "v0.1.0"` and
2702/// `:branch "main"` are both single-component refs, the canonical
2703/// leaf form for caixa's `:fonte` pin axes):
2704///
2705///   - 1..=[`GIT_REF_NAME_MAX_LEN`] (255) bytes — the POSIX `NAME_MAX`
2706///     filesystem-component limit Git's loose-ref `.git/refs/<cat>/<name>`
2707///     storage tops out at;
2708///   - no ASCII control characters (`0x00..=0x1F`, `0x7F`) — Git's
2709///     refname parser rejects them, and the `\r` / `\n` arms are the
2710///     canonical "the paste-from-doc spans multiple lines" footgun;
2711///   - no whitespace (space, tab) — Git's refname parser rejects them
2712///     too; a `:tag "v0.1.0 "` (trailing space, from a copy-paste)
2713///     silently passes string emptiness checks and fails at
2714///     `git fetch origin tag 'v0.1.0 '` with a quoting-confused error
2715///     far from the source caixa.lisp;
2716///   - no non-ASCII bytes (`>= 0x80`) — Git's refname rules predate
2717///     UTF-8 normalization (NFC vs NFD on APFS silently rewrites the
2718///     ref body, breaking the lacre's content addressing); the
2719///     intersection-floor every realistic Git host accepts is ASCII
2720///     identifiers + the small punctuation set below;
2721///   - no `~`, `^`, `:`, `?`, `*`, `[`, `\` anywhere — Git reserves
2722///     these for revision-grammar expressions (`HEAD~3`, `HEAD^`,
2723///     `:/searched`, glob wildcards, refspec brackets, Windows-path
2724///     backslash);
2725///   - no `@{` sequence — Git's reflog grammar (`HEAD@{2 hours ago}`,
2726///     `branch@{upstream}`);
2727///   - the bare `@` is not a valid refname (it's the alias for `HEAD`);
2728///   - no `..` anywhere (Git's `<rev1>..<rev2>` range syntax + the
2729///     `.` / `..` parent-traversal footgun);
2730///   - per `/`-separated component: must not begin with `.` (Git
2731///     refuses to follow loose `.git/refs/<cat>/.<name>` files), must
2732///     not end with `.lock` (Git's atomic-rename guard suffix), must
2733///     not be empty (`//` rejected by the no-empty-component arm
2734///     below);
2735///   - no leading `/`, no trailing `/`, no consecutive `//`;
2736///   - no trailing `.` on the whole ref (Git rejects `<name>.`);
2737///   - no `refs/heads/` or `refs/tags/` prefix — the canonical "I
2738///     copied the fully-qualified ref name out of `git show-ref`
2739///     instead of the leaf" footgun (per [`theory/FLAKE-DEDUP.md`][fd]
2740///     `BranchName` constructor rules); the caixa-resolver prepends
2741///     the category prefix at clone time, so an author-side
2742///     `:branch "refs/heads/main"` resolves to a literal ref named
2743///     `refs/heads/refs/heads/main` on disk.
2744///
2745/// Returns the parser-shaped reason on rejection (without wrapping in
2746/// any error variant) so each per-axis caller — `DepSource::validate`
2747/// for the `:fonte :tag` / `:fonte :branch` axes at validate time,
2748/// the future per-pin gate on `lacre.lisp` resolved-ref axes, the
2749/// future M4 per-dep CR materializer's per-pin validator — wraps the
2750/// same reason in its own typed `*Invalid { <axis>, reason }` variant.
2751/// The reason wording is axis-agnostic ("git ref names reject ASCII
2752/// control characters") so every call site reading the same diagnostic
2753/// points at the same rule; drift between any two axes' rule
2754/// enforcement is a build error visible at this predicate, not a
2755/// per-renderer "this passed validate but `git fetch` rejected at
2756/// clone time" surprise.
2757///
2758/// Empty input is rejected here (defensively) and at each call site
2759/// via the narrower [`crate::DepError::FontePinEmpty`] variant — the
2760/// same empty-first cascade [`is_dns_1123_label`],
2761/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
2762/// [`is_nats_subject`], and [`is_wasi_keyvalue_slot`] all carry.
2763///
2764/// `:rev` is intentionally NOT routed through this predicate — its
2765/// author-surface shape is a hex commit-ID (`[0-9a-f]+`), not a
2766/// refname; a dedicated `is_git_oid` predicate on the parallel
2767/// hex-shape trajectory carries the reproducibility contract. Routing
2768/// `:rev` through `is_git_ref_name` would admit `:rev "main"`,
2769/// defeating the reproducibility contract `:rev` carries vs.
2770/// `:branch` / `:tag`. The reverse mis-slot — a canonical OID
2771/// (40-char SHA-1 or 64-char SHA-256 lowercase hex) pasted into the
2772/// `:tag` / `:branch` slot — is closed by this predicate too: a
2773/// pre-emption arm below rejects any value whose width and byte set
2774/// match the canonical OID shape, surfacing the cross-axis mis-slot
2775/// at validate time with a diagnostic pointing the author at the
2776/// `:rev` slot. The two predicates' valid sets intersect at exactly
2777/// the empty set, structurally.
2778///
2779/// Lifted as a typed substrate-side primitive on the same trajectory
2780/// the peer value-shape predicates ([`is_dns_1123_label`],
2781/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
2782/// [`is_nats_subject`], [`is_wasi_keyvalue_slot`]) already follow —
2783/// the typed slot's valid set matches the Git porcelain's accepted
2784/// set, structurally. The sixth value-shape primitive to land in
2785/// [`crate::render`], and the first to gate a non-K8s downstream
2786/// landing surface (git CLI invocation from caixa-resolver, vs. the
2787/// K8s apiserver / NATS server / WASI kv backend for the prior five).
2788///
2789/// [gcr]: https://git-scm.com/docs/git-check-ref-format
2790/// [fd]: pleme-io/theory/FLAKE-DEDUP.md §1 `BranchName`
2791///
2792/// # Errors
2793///
2794/// Returns the parser-shaped reason naming the specific violation
2795/// (length / control-char / forbidden-char / component-shape / prefix),
2796/// without wrapping in any error variant — every caller maps the same
2797/// `String` into its own typed `*Invalid { <axis>, reason }` enum
2798/// variant.
2799pub fn is_git_ref_name(s: &str) -> Result<(), String> {
2800    if s.is_empty() {
2801        return Err("must not be empty".to_string());
2802    }
2803    if s.len() > GIT_REF_NAME_MAX_LEN {
2804        return Err(format!(
2805            "exceeds git ref name max length of {GIT_REF_NAME_MAX_LEN} bytes \
2806             (got {} bytes; legitimate tag/branch names rarely exceed ~32 bytes — \
2807             this length suggests a paste-from-binary or multi-line blob landed \
2808             in the `:tag` / `:branch` slot)",
2809            s.len()
2810        ));
2811    }
2812    // Canonical-OID-shape pre-emption — the structural partition the
2813    // doc-comment above promises and [`crate::DepSource::validate`]
2814    // routes the `:fonte` pin axes through ([`is_git_ref_name`] for
2815    // `:tag` + `:branch`, [`is_git_oid`] for `:rev`): a value that's
2816    // exactly the canonical Git commit-OID width
2817    // ([`GIT_OID_SHA1_LEN`] (40) lowercase-hex for SHA-1,
2818    // [`GIT_OID_SHA256_LEN`] (64) lowercase-hex for SHA-256) is the
2819    // shape `is_git_oid` accepts; the two predicates' valid sets must
2820    // intersect at exactly the empty set, so a value of that shape is
2821    // rejected here. Without this arm a canonical lowercase-hex OID of
2822    // either canonical width passes every other refname-shape arm in
2823    // this predicate — pure-hex strings carry none of the forbidden
2824    // characters, no `..` / `@{` / leading-`/` / trailing-`/` /
2825    // `.lock`-suffix / `refs/heads/`-prefix — and the cross-axis
2826    // partition silently fails on the canonical "I copied the SHA out
2827    // of `git show --format=%H` and pasted it into `:tag` / `:branch`"
2828    // mis-slot footgun. The pleme-io discipline (CAIXA-SDLC §V — the
2829    // `:rev` slot carries the reproducibility contract; `:tag` /
2830    // `:branch` resolve to whatever the upstream has tagged / `HEAD`
2831    // today) requires that an OID-shaped value live under `:rev`, never
2832    // under `:tag` / `:branch`; this arm makes that discipline a typed
2833    // structural property, not a convention.
2834    //
2835    // Uppercase hex (`"DEADBEEF…"` 40 chars) is intentionally NOT
2836    // matched here — uppercase letters are legitimate in refnames per
2837    // `git check-ref-format`, so an uppercase 40/64-char hex string is a
2838    // valid refname (`is_git_ref_name` accepts it); the `:rev` axis
2839    // separately rejects uppercase via [`is_git_oid`]'s lowercase-only
2840    // contract. Off-canonical lengths (39 / 41 / 63 / 65 hex chars) are
2841    // also intentionally NOT matched — abbreviated commit IDs are
2842    // ambiguous across repository history but they're not canonical
2843    // OIDs either; they remain accepted as refnames here (consistent
2844    // with `is_git_oid` already rejecting them via its exact-width
2845    // check).
2846    if (s.len() == GIT_OID_SHA1_LEN || s.len() == GIT_OID_SHA256_LEN)
2847        && s.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'f'))
2848    {
2849        return Err(format!(
2850            "looks like a canonical Git commit OID ({len} lowercase hex \
2851             characters — the SHA-{algo} OID width); pleme-io's `:fonte` axes \
2852             partition refnames vs. commit OIDs structurally, so a value of \
2853             this shape belongs in the `:rev` slot (which routes through \
2854             `is_git_oid` for the reproducibility contract — one immutable \
2855             commit, forever), not `:tag` / `:branch` (which route through \
2856             this predicate for human-readable refs `git fetch` resolves at \
2857             clone time). Move the value to `:rev`; keeping it under `:tag` \
2858             / `:branch` is the canonical paste-from-`git show --format=%H` \
2859             mis-slot footgun, silently demoting an OID to a refname-shaped \
2860             pin the resolver would attempt to `git fetch tag '<sha>'` and \
2861             fail at clone time with a quoting-confused porcelain error far \
2862             from the source caixa.lisp.",
2863            len = s.len(),
2864            algo = if s.len() == GIT_OID_SHA1_LEN {
2865                "1"
2866            } else {
2867                "256"
2868            },
2869        ));
2870    }
2871    if s.starts_with('-') {
2872        return Err(
2873            "must not start with `-` (the canonical CLI-argument-injection \
2874             footgun on the `:tag` / `:branch` axis — caixa-resolver's \
2875             `git::checkout` invocation routes the ref name verbatim into \
2876             `git checkout --quiet --detach <ref>` (caixa-resolver/src/git.rs:41) \
2877             without a `--` argument-list terminator, so a leading `-` value \
2878             (`:tag \"-stable\"`, `:branch \"-X\"`, `:tag \"-c=core.merge=ours\"`) \
2879             silently escapes the subprocess argument boundary and gets \
2880             reinterpreted by `git checkout`'s argument parser as a CLI flag — \
2881             the canonical short-flag / long-option / config-injection vector. \
2882             Git's `check-ref-format` grammar does NOT reject a leading `-` \
2883             (it admits the byte mid-name as a legitimate kebab separator), so \
2884             every prior shape arm on this predicate passes the value through; \
2885             the diagnostic moves the gate to the subprocess-argument \
2886             boundary the resolver consumes. Peer with the \
2887             [`is_git_repo_url`] leading-`-` arm (the CLI-arg-injection \
2888             vector on the sibling `:repo` axis where `git clone <repo>` \
2889             reinterprets a leading `-` as a flag like `-upload-pack=…` / \
2890             `--config=…`), [`is_cargo_feature_name`] leading-`-` arm, and \
2891             [`is_dns_1123_label`] leading-`-` arm — every single-token typed \
2892             string slot the substrate routes through a downstream subprocess \
2893             / parser rejects the same leading-byte CLI-arg-injection shape \
2894             at validate time. Drop the leading `-`; use a kebab-separator-\
2895             between-alphanumeric-segments form like `\"v0.1.0\"` / \
2896             `\"feature-x\"` / `\"main\"` instead)"
2897                .to_string(),
2898        );
2899    }
2900    for &b in s.as_bytes() {
2901        if b == b' ' || b == b'\t' {
2902            return Err(format!(
2903                "must not contain whitespace character {ch:?} (git ref names are \
2904                 single tokens with no whitespace — a trailing space in a `:tag` \
2905                 / `:branch` value is the canonical paste-from-doc footgun, \
2906                 silently breaking `git fetch <remote> tag '<value> '` at \
2907                 clone time)",
2908                ch = b as char
2909            ));
2910        }
2911        if b < 0x20 || b == 0x7F {
2912            return Err(format!(
2913                "must not contain control character 0x{b:02x} (git ref names are \
2914                 printable ASCII; `\\r` / `\\n` are the canonical \
2915                 paste-from-multiline-doc footgun and break git's refname parser \
2916                 at every porcelain entry point)"
2917            ));
2918        }
2919        if b >= 0x80 {
2920            return Err(format!(
2921                "must not contain non-ASCII byte 0x{b:02x} (git's refname rules \
2922                 predate UTF-8 normalization — APFS NFC/NFD silently rewrites the \
2923                 ref body, breaking the lacre's content addressing across \
2924                 platforms; the intersection-floor every git host admits is ASCII)"
2925            ));
2926        }
2927        match b {
2928            b'~' => {
2929                return Err("must not contain `~` (git reserves `~` for the revision \
2930                     grammar — `HEAD~3` means `parent of parent of parent of \
2931                     HEAD`; the bare character is not admitted in a refname)"
2932                    .to_string());
2933            }
2934            b'^' => {
2935                return Err("must not contain `^` (git reserves `^` for the revision \
2936                     grammar — `HEAD^` means `first parent of HEAD`; the bare \
2937                     character is not admitted in a refname)"
2938                    .to_string());
2939            }
2940            b':' => {
2941                return Err("must not contain `:` (git reserves `:` for revspec / \
2942                     refspec separators — `:refs/heads/...`, `<src>:<dst>`)"
2943                    .to_string());
2944            }
2945            b'?' => {
2946                return Err("must not contain `?` (git reserves `?` for refspec glob \
2947                     wildcards)"
2948                    .to_string());
2949            }
2950            b'*' => {
2951                return Err("must not contain `*` (git reserves `*` for refspec glob \
2952                     wildcards — `refs/heads/*:refs/remotes/origin/*`)"
2953                    .to_string());
2954            }
2955            b'[' => {
2956                return Err("must not contain `[` (git reserves `[` for refspec \
2957                     bracketed-glob syntax)"
2958                    .to_string());
2959            }
2960            b'\\' => {
2961                return Err("must not contain `\\` (git's refname grammar rejects \
2962                     backslash — the canonical Windows-path-leak footgun; use \
2963                     `/` for hierarchical refs)"
2964                    .to_string());
2965            }
2966            _ => {}
2967        }
2968    }
2969    if s.contains("..") {
2970        return Err(
2971            "must not contain `..` (git reserves `..` for the `<rev1>..<rev2>` \
2972             range grammar; a `..` component would also escape the loose-ref \
2973             directory tree at clone time)"
2974                .to_string(),
2975        );
2976    }
2977    if s.contains("@{") {
2978        return Err(
2979            "must not contain `@{` (git reserves `@{` for the reflog grammar \
2980             — `branch@{upstream}`, `HEAD@{2 hours ago}`)"
2981                .to_string(),
2982        );
2983    }
2984    if s == "@" {
2985        return Err(
2986            "must not be the bare `@` (git aliases `@` to `HEAD`; a `:tag` / \
2987             `:branch` named `@` is unsourceable)"
2988                .to_string(),
2989        );
2990    }
2991    if s.starts_with('/') {
2992        return Err(
2993            "must not begin with `/` (git refnames are relative to the ref \
2994             category prefix the resolver prepends — drop the leading `/`)"
2995                .to_string(),
2996        );
2997    }
2998    if s.ends_with('/') {
2999        return Err(
3000            "must not end with `/` (git refnames are leaf-or-multi-component; \
3001             a trailing `/` would resolve to an empty final component)"
3002                .to_string(),
3003        );
3004    }
3005    if s.contains("//") {
3006        return Err(
3007            "must not contain consecutive `/` characters (git refnames reject \
3008             empty components between separators)"
3009                .to_string(),
3010        );
3011    }
3012    if s.ends_with('.') {
3013        return Err(
3014            "must not end with `.` (git refnames reject a trailing `.` — \
3015             `<name>.` collides with the `<name>.lock` atomic-rename guard \
3016             suffix on case-insensitive filesystems)"
3017                .to_string(),
3018        );
3019    }
3020    if s.starts_with("refs/heads/") || s.starts_with("refs/tags/") {
3021        return Err(format!(
3022            "must not carry the fully-qualified `refs/heads/` or `refs/tags/` \
3023             prefix (this is the canonical `git show-ref` output-leak footgun; \
3024             the caixa-resolver prepends the category prefix at clone time, so \
3025             a `:branch \"refs/heads/main\"` would resolve to a literal ref \
3026             named `refs/heads/refs/heads/main` on disk — drop the prefix and \
3027             pass the leaf: `{leaf:?}`)",
3028            leaf = s
3029                .strip_prefix("refs/heads/")
3030                .or_else(|| s.strip_prefix("refs/tags/"))
3031                .unwrap_or(s),
3032        ));
3033    }
3034    for (i, component) in s.split('/').enumerate() {
3035        if component.starts_with('.') {
3036            return Err(format!(
3037                "component {component:?} (segment {one_based} of the `/`-split \
3038                 refname) must not begin with `.` (git refuses to follow loose \
3039                 `.git/refs/<cat>/.<name>` files)",
3040                one_based = i + 1,
3041            ));
3042        }
3043        // Case-insensitive `.lock` check: git enforces the `.lock`
3044        // suffix as the atomic-rename guard on case-sensitive
3045        // filesystems (refs/heads/main.lock collides with the
3046        // in-flight update lockfile); on case-insensitive
3047        // filesystems (APFS default, NTFS, HFS+) the `.LOCK` /
3048        // `.Lock` variants collide identically. Rejecting all case
3049        // permutations matches the broader-rejection intent on the
3050        // axis the lacre pipeline ultimately stores into.
3051        if component.len() >= 5
3052            && component.as_bytes()[component.len() - 5..].eq_ignore_ascii_case(b".lock")
3053        {
3054            return Err(format!(
3055                "component {component:?} (segment {one_based} of the `/`-split \
3056                 refname) must not end with `.lock` (git uses the `.lock` \
3057                 suffix as the atomic-rename guard for in-flight ref updates; \
3058                 a refname ending in `.lock` is unwritable, and the suffix is \
3059                 case-insensitive on the case-insensitive filesystems Git \
3060                 supports — APFS default, NTFS, HFS+)",
3061                one_based = i + 1,
3062            ));
3063        }
3064    }
3065    Ok(())
3066}
3067
3068/// Length, in lowercase-hex characters, of a full Git SHA-1 commit
3069/// OID — the canonical commit identifier every `git rev-parse HEAD`
3070/// invocation emits on a SHA-1-hashed repository. `git`'s loose-object
3071/// store keys every object under `.git/objects/<first-2-hex>/<last-38-hex>`,
3072/// so the full 40-char OID is the address-of-truth the porcelain consumes
3073/// at `git fetch <remote> <40-hex>` and `git checkout <40-hex>` time;
3074/// abbreviated OIDs are admitted by the porcelain through a separate
3075/// prefix-lookup pass and are ambiguous across repository history (a 7-char
3076/// prefix that resolves to one commit today can become a collision tomorrow
3077/// as the repo grows). Lifted as a typed const so the `:fonte :rev`
3078/// validate gate, the future lacre-side resolved-rev gate, and the future
3079/// M4 per-dep CR materializer's per-pin validator all read from one place.
3080pub const GIT_OID_SHA1_LEN: usize = 40;
3081
3082/// Length, in lowercase-hex characters, of a full Git SHA-256 commit
3083/// OID — the canonical commit identifier on a SHA-256-hashed repository
3084/// (Git's [`extensions.objectFormat = sha256`][gitsha256] mode, GA since
3085/// Git 2.42 / Oct 2023). Doubled width vs. SHA-1: 256 bits = 64 hex chars.
3086/// Carried alongside [`GIT_OID_SHA1_LEN`] so the typed `:rev` slot admits
3087/// either canonical hash-algorithm OID without per-renderer branching;
3088/// the lacre's BLAKE3 content-addressing (THEORY.md §IV — typed reproducibility
3089/// envelope) is orthogonal to the upstream git's chosen object hash and
3090/// neither OID width should leak into downstream code paths.
3091///
3092/// [gitsha256]: https://git-scm.com/docs/hash-function-transition
3093pub const GIT_OID_SHA256_LEN: usize = 64;
3094
3095/// Predicate: assert that `s` is a valid Git commit OID — the canonical
3096/// shape the typed `:fonte (:tipo git …)` `:rev` axis carries. The
3097/// reproducibility contract `:rev` carries vs. `:tag` / `:branch`
3098/// (CAIXA-SDLC §V — Substrate; `:tag` resolves to whatever the upstream
3099/// has tagged today, `:branch` to whatever the upstream's HEAD points at
3100/// today, `:rev` to exactly one immutable commit forever — same shape
3101/// Unison's [content-addressed code identity][unison] gives terms by
3102/// construction: the hash is the address, the address never moves):
3103///
3104///   - exactly [`GIT_OID_SHA1_LEN`] (40, SHA-1) or [`GIT_OID_SHA256_LEN`]
3105///     (64, SHA-256) characters — the two canonical Git hash-algorithm
3106///     widths; anything in between is an abbreviated prefix (the
3107///     canonical `git log --short` / `git rev-parse --short HEAD`
3108///     paste-from-release-notes footgun), which is ambiguous across
3109///     repository history and surfaces at clone time as an
3110///     [`ambiguous argument`][gitambig] error far from the source
3111///     caixa.lisp;
3112///   - every byte in `[0-9a-f]` (lowercase ASCII hex) — `git rev-parse`
3113///     and `git show --format=%H` both emit lowercase exclusively, so an
3114///     uppercase-bearing `:rev` round-trips inconsistently across the
3115///     resolver's `git fetch <remote> <:rev>` ↔ `git rev-parse HEAD`
3116///     equality-check pipeline and fails the lacre's content-addressing
3117///     equality probe with a confusing case-only diff;
3118///   - no whitespace, no control bytes, no non-ASCII, no refname
3119///     punctuation (`~ ^ : ? * [ \`), no `/` separators — every
3120///     character outside `[0-9a-f]` is rejected on the same predicate
3121///     arm, so a `:rev "main"` (the canonical "I conflated `:rev`
3122///     and `:branch`" footgun) lands at the same gate as a
3123///     `:rev "v0.1.0"` (`:tag` mis-slot) or a `:rev "c0ffee:scratch"`
3124///     (refname-shape leak); the typed `:rev` slot's valid set
3125///     intersects the `:tag` / `:branch` slot's valid set at exactly
3126///     the empty set, structurally — every refname is rejected here,
3127///     every OID is rejected by [`is_git_ref_name`].
3128///   - not the all-zero null-OID sentinel (`"0000…0000"` — 40 zeros
3129///     at SHA-1 width, 64 zeros at SHA-256 width). Git reserves this
3130///     value as the "no commit" sentinel in `git update-ref` /
3131///     pre-receive hook flows (`<old-value>` for create, `<new-value>`
3132///     for delete) and no commit in any object database has this OID,
3133///     so a `:rev "0000…0000"` is structurally impossible to resolve.
3134///     The canonical "I copy-pasted the sentinel out of `git
3135///     update-ref --stdin` docs / pre-receive hook example" footgun
3136///     would otherwise pass every other shape arm (canonical length,
3137///     lowercase hex) and surface at `git fetch <remote> 0000…0000`
3138///     time with a quoting-confused "couldn't find remote ref" error
3139///     far from the source caixa.lisp, with the lacre's content-
3140///     address locked to a `git:0000…0000` closure that never equals
3141///     any upstream's actual `HEAD`. Mirrors `is_git_ref_name`'s
3142///     canonical-OID-shape pre-emption arm (line 1322) — both
3143///     predicates carry one self-aware arm that catches values
3144///     structurally valid for the alphabet but operationally
3145///     meaningless on the typed axis.
3146///
3147/// Returns the parser-shaped reason on rejection (without wrapping in
3148/// any error variant) so each per-axis caller — [`crate::DepError::FontePinShape`]
3149/// at validate time on the `:fonte :rev` axis, the future per-pin gate
3150/// on `lacre.lisp` resolved-rev axes, the future M4 per-dep CR
3151/// materializer's per-pin validator — wraps the same reason in its own
3152/// typed `*Invalid { axis, reason }` variant. The reason wording is
3153/// axis-agnostic ("git commit OIDs are lowercase hex (`[0-9a-f]`)") so
3154/// every call site reading the same diagnostic points at the same rule.
3155///
3156/// Empty input is rejected here (defensively) and at each call site via
3157/// the narrower [`crate::DepError::FontePinEmpty`] variant — the same
3158/// empty-first cascade [`is_dns_1123_label`], [`is_gateway_api_http_path`],
3159/// [`is_wit_world_ref`], [`is_nats_subject`], [`is_wasi_keyvalue_slot`],
3160/// and [`is_git_ref_name`] all carry.
3161///
3162/// Sibling of [`is_git_ref_name`]: the two predicates together bracket
3163/// the `:fonte` pin axes — refname-shaped (`:tag` / `:branch`) vs.
3164/// hex-OID-shaped (`:rev`) — so an authored value lands in exactly one
3165/// of the two valid sets, and a cross-axis mis-slot (`:rev "main"` /
3166/// `:tag "deadbeef…"`) is a build error at the offending axis's
3167/// predicate, not a clone-time surprise.
3168///
3169/// [unison]: https://www.unison-lang.org/docs/the-big-idea/
3170/// [gitambig]: https://git-scm.com/docs/git-rev-parse#_specifying_revisions
3171///
3172/// # Errors
3173///
3174/// Returns the parser-shaped reason naming the specific violation
3175/// (length / character-class), without wrapping in any error variant —
3176/// every caller maps the same `String` into its own typed
3177/// `*Invalid { axis, reason }` enum variant.
3178pub fn is_git_oid(s: &str) -> Result<(), String> {
3179    if s.is_empty() {
3180        return Err("must not be empty".to_string());
3181    }
3182    let len = s.len();
3183    if len != GIT_OID_SHA1_LEN && len != GIT_OID_SHA256_LEN {
3184        return Err(format!(
3185            "git commit OIDs are exactly {GIT_OID_SHA1_LEN} hex chars (SHA-1) or \
3186             {GIT_OID_SHA256_LEN} hex chars (SHA-256); got {len} chars (an \
3187             abbreviated commit ID is ambiguous across repository history — \
3188             `git log --short` / `git rev-parse --short HEAD` emit prefixes for \
3189             human display only, not as reproducible commit addresses; pin the \
3190             full OID so the resolver's `git fetch <remote> <:rev>` and the \
3191             lacre's content-addressing equality probe both resolve to exactly \
3192             one immutable commit, forever)"
3193        ));
3194    }
3195    for (i, b) in s.bytes().enumerate() {
3196        match b {
3197            b'0'..=b'9' | b'a'..=b'f' => {}
3198            b'A'..=b'F' => {
3199                return Err(format!(
3200                    "git commit OIDs are lowercase hex (`[0-9a-f]`); got \
3201                     uppercase character {ch:?} at byte {i} (git porcelain \
3202                     emits OIDs lowercase exclusively — `git rev-parse HEAD` \
3203                     and `git show --format=%H` both lowercase on output; a \
3204                     `:rev` value with `[A-F]` round-trips inconsistently \
3205                     across the resolver's fetch ↔ `git rev-parse HEAD` \
3206                     equality-check pipeline and fails the lacre's \
3207                     content-addressing probe with a confusing case-only diff)",
3208                    ch = b as char
3209                ));
3210            }
3211            _ => {
3212                return Err(format!(
3213                    "git commit OIDs are lowercase hex (`[0-9a-f]`); got non-hex \
3214                     character {ch:?} at byte {i} (the `:rev` slot's value-shape \
3215                     contract is a hex commit ID — for refname-shaped pins \
3216                     (`v0.1.0`, `main`, `feature/checkout`) use `:tag` or \
3217                     `:branch`, not `:rev`; the substrate's `is_git_ref_name` \
3218                     and `is_git_oid` predicates partition the `:fonte` axes \
3219                     structurally, so a cross-axis mis-slot lands at the \
3220                     offending axis's predicate, not at clone time)",
3221                    ch = b as char
3222                ));
3223            }
3224        }
3225    }
3226    // Null-OID sentinel pre-emption — the all-zero hex string is git's
3227    // canonical "no commit" sentinel (used in `git update-ref` /
3228    // pre-receive hook flows as the old-value side of ref-create and the
3229    // new-value side of ref-delete) and never names a real commit in any
3230    // repo's object database. A `:rev "0000000000000000000000000000000000000000"`
3231    // (SHA-1 width) or `:rev "0000…0000"` (SHA-256 width) is the canonical
3232    // "I copy-pasted the no-such-commit sentinel out of `git
3233    // update-ref --stdin` docs / pre-receive hook example" footgun: it's
3234    // shape-valid hex of canonical width but resolves to nothing at
3235    // `git fetch <remote> 0000…0000` time and surfaces as a fetch failure
3236    // far from the source caixa.lisp, with the lacre's
3237    // content-addressing probe locked to a non-resolvable `git:0000…0000`
3238    // closure that never equals any upstream's actual `HEAD`. Rejecting
3239    // at the predicate keeps the `:rev` slot's accepted set aligned with
3240    // its documented reproducibility contract — "exactly one immutable
3241    // commit, forever" — by structurally refusing the only OID-shaped
3242    // value the contract cannot uphold (no commit means no immutable
3243    // resolution). Same pre-emption shape `is_git_ref_name`'s canonical-
3244    // OID-shape pre-emption arm (caixa-core/src/render.rs:1322) carries
3245    // — both predicates carry one self-aware arm that catches values
3246    // structurally valid for the alphabet but operationally meaningless
3247    // on the typed axis.
3248    if s.bytes().all(|b| b == b'0') {
3249        return Err(format!(
3250            "must not be the all-zero null-OID sentinel ({len} `0` \
3251             characters — git's canonical `no-such-commit` value used by \
3252             `git update-ref` / pre-receive hook flows to indicate ref \
3253             create/delete; no commit in any object database has this OID, \
3254             so the resolver's `git fetch <remote> 0000…0000` would fail \
3255             far from the source caixa.lisp and the lacre would lock to a \
3256             `git:0000…0000` closure that never equals any upstream's \
3257             actual `HEAD`. The `:rev` slot's reproducibility contract \
3258             requires a *real* commit OID — the canonical authoring shape \
3259             is the lowercase-hex value `git rev-parse HEAD` emits for an \
3260             actual commit, like `\"c99fdb36abc7d3e1f4a5b6789012345678901234\"`)"
3261        ));
3262    }
3263    Ok(())
3264}
3265
3266/// `:fonte (:tipo git :repo …)` value max length, in bytes — a generous
3267/// URL-shaped cap covering every documented author surface (the
3268/// `github:org/repo` shorthand, the `https://` / `ssh://` / `git://` /
3269/// `file://` URL schemes, the `git@host:path` scp-style SSH form). The
3270/// cap mirrors the conservative ceiling typical HTTP gateways and git
3271/// porcelain entries enforce on URL inputs (the OWASP-recommended URL
3272/// max of 2048 bytes); a `:repo` value above this bound is structurally
3273/// untenable on every realistic landing site — the caixa-resolver's
3274/// `git clone <repo>` invocation, the future M4
3275/// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-dep `repo:`
3276/// axis, the future lacre BLAKE3 closure's resolved-repo identity — and
3277/// a value of that length is almost certainly a paste-from-binary slug
3278/// or a multi-line blob that landed in the slot.
3279///
3280/// Lifted as a typed `pub const` (rather than an inline literal at the
3281/// [`is_git_repo_url`] call site) so a future axis reaching for the same
3282/// bound (the future lacre-side resolved-repo gate, the M4 CR
3283/// materializer's per-dep `repo:` admission webhook) reads from one
3284/// place. Same shape every other typed bound in this module carries
3285/// ([`DNS_1123_LABEL_MAX_LEN`], [`GATEWAY_API_HTTP_PATH_MAX_LEN`],
3286/// [`NATS_SUBJECT_MAX_LEN`], [`WASI_KV_SLOT_MAX_LEN`],
3287/// [`GIT_REF_NAME_MAX_LEN`]).
3288pub const GIT_REPO_URL_MAX_LEN: usize = 2048;
3289
3290/// Predicate: assert that `s` is a value-shape-valid `:fonte (:tipo git
3291/// :repo …)` value — the canonical shape every typed `:deps :fonte`
3292/// (and future `:deps-dev :fonte`) git-source carries. The contract —
3293/// modeled on the intersection of (a) the git porcelain's URL-parser
3294/// accepted set the caixa-resolver invokes at `git clone <repo>` time,
3295/// (b) the OWASP URL-shape guidance for author-surface inputs that flow
3296/// to a CLI subprocess, and (c) the typed slot's documented accepted
3297/// shapes ([`crate::DepSource::Git`] doc comment: `github:org/repo`
3298/// shorthand, `https://…` / `ssh://…` / `git://…` / `file://…` URL
3299/// schemes, `git@host:path` scp-style SSH):
3300///
3301///   - 1..=[`GIT_REPO_URL_MAX_LEN`] (2048) bytes;
3302///   - must not start with `-` (the canonical CLI-argument-injection
3303///     footgun — `git clone <repo>` interprets a leading `-` as a CLI
3304///     flag, so a `:repo "-upload-pack=evil"` value escapes the
3305///     subprocess argument boundary and runs an attacker-controlled
3306///     command; the `--` separator workaround does not fix the typed
3307///     slot's accepted set, the gate rejects the shape upstream);
3308///   - no whitespace (space, tab) — every documented form is a single
3309///     token without whitespace; a `:repo "github:p/x "` (trailing
3310///     space, paste-from-doc) silently passes the empty check and
3311///     surfaces at `git clone` time with a quoting-confused error far
3312///     from the source caixa.lisp;
3313///   - no ASCII control characters (`0x00..=0x1F`, `0x7F`) — the `\r`
3314///     / `\n` arms are the canonical "the paste-from-multiline-doc
3315///     spans multiple lines" footgun, and CRLF injection at the URL
3316///     boundary is a class of subprocess-arg attack;
3317///   - no non-ASCII bytes (`>= 0x80`) — IDN hosts must be pre-encoded
3318///     as Punycode (`xn--…`); raw non-ASCII silently breaks at git's
3319///     URL parser and may round-trip inconsistently across NFC/NFD
3320///     normalization on APFS / case-folding filesystems, the same
3321///     intersection-floor [`is_git_ref_name`] enforces on the peer
3322///     refname axes;
3323///   - no `#` URL-fragment-identifier byte (RFC 3986 §3.5) — every
3324///     documented `:repo` shape (`github:org/repo` shorthand,
3325///     `https://…` / `ssh://…` / `git://…` / `file://…` URL schemes,
3326///     `git@host:path` scp-style SSH) carries none; libcurl's URL
3327///     parser (the layer `git clone <https-url>` invokes) and git's
3328///     own URL handlers strip the `#fragment` tail before opening
3329///     the transport, so the byte rides verbatim into the lacre's
3330///     per-dep content-address (`conteudo: format!("git:{repo}…")`,
3331///     caixa-resolver/src/resolve.rs) but is silently dropped on the
3332///     wire — two repos whose values differ only in their fragment
3333///     anchor (`":repo "https://github.com/foo/bar#readme"` vs
3334///     `":repo "https://github.com/foo/bar#L42"`) resolve to the
3335///     byte-identical upstream `git clone` but lock to two distinct
3336///     BLAKE3 closures, defeating the THEORY.md §V.2 render-
3337///     determinism contract. The canonical "I copy-pasted the
3338///     permalink-to-line / anchor-to-README URL out of the browser
3339///     address bar and forgot to trim the `#`-tail" footgun, and the
3340///     symmetric "I confused the Nix flake-ref idiom (`github:foo/
3341///     bar#packageName`) with the bare git `:repo` shape" footgun;
3342///     `:repo` is a git URL, not a Nix flake reference, so the `#`-
3343///     suffix is structurally meaningless on this axis;
3344///   - no `?` URL-query-component byte (RFC 3986 §3.4) — every
3345///     documented `:repo` shape (`github:org/repo` shorthand,
3346///     `https://…` / `ssh://…` / `git://…` / `file://…` URL schemes,
3347///     `git@host:path` scp-style SSH) carries none; GitHub /
3348///     GitLab / Bitbucket all silently ignore the `?query` tail on
3349///     a repo URL (the canonical `https://github.com/foo/bar?
3350///     tab=readme-ov-file` browser-tab deep-link, the `?ref=main`
3351///     GitHub-tree-URL parameter, the `?utm_source=…` campaign-
3352///     tracker shape every social-share / newsletter / Slack
3353///     unfurl appends) and serve the same repo regardless, so the
3354///     byte rides verbatim into the lacre's per-dep content-
3355///     address but is silently masked at the wire — two repos
3356///     whose values differ only in their query tail
3357///     (`":repo "https://github.com/foo/bar?tab=readme-ov-file"` vs
3358///     `":repo "https://github.com/foo/bar?utm_source=twitter"`)
3359///     resolve to the byte-identical upstream `git clone` but lock
3360///     to two distinct BLAKE3 closures, defeating the THEORY.md
3361///     §V.2 render-determinism contract on the same axis the `#`
3362///     fragment arm closes. The Smart-HTTP transport (the layer
3363///     `git clone <https-url>` uses) appends its own
3364///     `?service=git-upload-pack` query internally; an
3365///     author-supplied `?` byte additionally collides with that
3366///     internal axis at every git porcelain entry-point. The
3367///     canonical "I copy-pasted the GitHub tree-URL out of the
3368///     browser address bar and forgot to trim the `?tab=…` /
3369///     `?ref=…` tail" footgun, peer with the `#` fragment arm on
3370///     the same paste-from-browser-address-bar trajectory;
3371///   - no embedded `\` byte (RFC 3986 §3.3 reserves `/` as the path-
3372///     segment separator; no URL grammar admits `\`) — every
3373///     documented `:repo` shape (`github:org/repo` shorthand,
3374///     `https://…` / `ssh://…` / `git://…` / `file://…` URL schemes,
3375///     `git@host:path` scp-style SSH) uses `/` as the path separator.
3376///     The canonical Windows-path-confusion footgun: an author
3377///     pastes `file:///C:\Users\me\repo` from a Windows Explorer
3378///     address bar / PowerShell `Get-Location` output, or
3379///     `https://github.com\foo\bar` after a Win32 shell mangled
3380///     the slashes, or the bare Windows-rooted path `C:\repo` into
3381///     a slot expecting a `file://` URL. libcurl's URL parser
3382///     (the layer `git clone <https-url>` invokes) silently
3383///     translates `\` → `/` on some platforms and refuses it on
3384///     others — the byte rides verbatim into the lacre's per-dep
3385///     content-address but is silently rewritten or rejected at
3386///     the wire, defeating the THEORY.md §V.2 render-determinism
3387///     contract on the same axis the `#` fragment / `?` query arms
3388///     close. The peer [`DepError::FonteCaminhoBackslash`] arm
3389///     (commit 3a4e1d7) closes the same byte on the sibling
3390///     `:fonte :caminho` path-fonte axis; this arm closes the
3391///     URL-grammar axis so every byte past `is_git_repo_url`
3392///     reaches `git clone`'s wire-format intact;
3393///   - no embedded `{` / `}` byte — RFC 3986 §2 excludes the pair
3394///     from URL syntax (they sit in the 'delims' / 'unwise' byte
3395///     set every URL parser is required to refuse or percent-
3396///     encode), and RFC 6570 reserves the matched pair for URI
3397///     Template placeholders (the canonical
3398///     `https://{host}/{org}/{repo}` substitution shape every
3399///     `OpenAPI` / Swagger / Postman / GitHub Octokit client library
3400///     / Helm chart-URL fragment carries). The canonical 'I forgot
3401///     to resolve the template placeholder' footgun: an author
3402///     pastes `:repo "https://github.com/{org}/{repo}"` from a
3403///     README quick-start snippet, an `OpenAPI` `servers:` URL, a
3404///     Helm chart's `home:` template, or the Mustache / Handlebars
3405///     `{{org}}/{{repo}}` doubled-brace substitution form every
3406///     CI / `IaC` templating engine emits, expecting the substrate
3407///     to resolve the placeholder downstream. libcurl percent-
3408///     encodes `{` / `}` to `%7B` / `%7D` on the wire so the byte
3409///     round-trips inconsistently between the lacre's per-dep
3410///     content-address and the resolver's `git clone <repo>`
3411///     invocation, defeating the THEORY.md §V.2 render-
3412///     determinism contract on the same axis the `#` fragment /
3413///     `?` query / `\` backslash arms close; every git porcelain
3414///     entry-point additionally fetches a nonexistent
3415///     `{placeholder}`-named path far from the source caixa.lisp;
3416///   - no embedded `<` / `>` byte — RFC 3986 §2 excludes the pair
3417///     from URL syntax under the same 'delims' / 'unwise' banner the
3418///     `{` / `}` arm cites, and no git URL grammar admits either byte:
3419///     the WHATWG URL spec's 'fragment percent-encode set' maps `<`
3420///     → `%3C` and `>` → `%3E` so every conformant URL parser
3421///     refuses or rewrites the literal byte on the wire. Beyond the
3422///     URL-grammar violation, every POSIX shell lexes `<` as the
3423///     input-redirection operator and `>` as the output-redirection
3424///     operator — the canonical paste-from-shell-prompt footgun the
3425///     peer [`DepError::FonteCaminhoShellRedirection`] arm
3426///     (commit e457141) closes on the sibling `:fonte :caminho`
3427///     path-fonte axis. The byte rides verbatim into the lacre's
3428///     per-dep content-address while libcurl percent-encodes it on
3429///     the wire — two authors whose `:repo` values differ only in
3430///     `<`/`>` presence resolve to the byte-identical upstream
3431///     `git clone` but lock to two distinct BLAKE3 closures,
3432///     defeating the THEORY.md §V.2 render-determinism contract on
3433///     the same axis the `#` fragment / `?` query / `\` backslash /
3434///     `{` / `}` template arms close;
3435///   - no embedded `` ` `` (backtick) byte — RFC 3986 §2 lists the
3436///     backtick in the 'delims' / 'unwise' set every URL parser is
3437///     required to refuse or percent-encode, and no git URL grammar
3438///     admits the byte: the WHATWG URL spec's 'fragment percent-
3439///     encode set' maps `` ` `` → `%60` so every conformant URL
3440///     parser refuses or rewrites the literal byte on the wire.
3441///     Beyond the URL-grammar violation, every POSIX shell lexes the
3442///     backtick as the legacy command-substitution operator
3443///     (`` `<cmd>` `` runs `<cmd>` in a subshell and substitutes its
3444///     stdout) — the canonical paste-from-shell-prompt RCE-class
3445///     footgun the peer [`crate::DepError::FonteCaminhoShellCommandSubstitution`]
3446///     arm (commit c4d62b3) closes on the sibling `:fonte :caminho`
3447///     path-fonte axis. The byte rides verbatim into the lacre's
3448///     per-dep content-address while libcurl percent-encodes it on
3449///     the wire — two authors whose `:repo` values differ only in
3450///     backtick presence resolve to the byte-identical upstream `git
3451///     clone` but lock to two distinct BLAKE3 closures, defeating
3452///     the THEORY.md §V.2 render-determinism contract on the same
3453///     axis the `#` fragment / `?` query / `\` backslash / `{` / `}`
3454///     template / `<` / `>` shell-redirection arms close;
3455///   - must contain a `:` separator at a non-leading position — every
3456///     documented form carries one (`github:org/repo`, `https://…`,
3457///     `ssh://…`, `git://…`, `file://…`, `git@host:path`); the
3458///     bare `org/repo` (no scheme) shape is ambiguous (could be a
3459///     filesystem path or a missing scheme) and silently passes
3460///     downstream git porcelain as a local relative path rather than
3461///     the intended GitHub-shorthand expansion. A leading `:` (`":foo"`)
3462///     is the canonical "empty scheme" footgun and is rejected too.
3463///
3464/// Returns the parser-shaped reason on rejection (without wrapping in
3465/// any error variant) so each per-axis caller — [`crate::DepError::FonteRepoShape`]
3466/// at validate time on the `:fonte :repo` axis, the future per-pin gate
3467/// on `lacre.lisp` resolved-repo axes, the future M4 per-dep CR
3468/// materializer's per-repo validator — wraps the same reason in its
3469/// own typed `*Invalid { axis, reason }` variant. The reason wording is
3470/// axis-agnostic ("git repo URLs reject whitespace") so every call site
3471/// reading the same diagnostic points at the same rule; drift between
3472/// any two axes' rule enforcement is a build error visible at this
3473/// predicate, not a per-resolver "this passed validate but `git clone`
3474/// rejected" surprise.
3475///
3476/// Empty input is rejected here (defensively) and at each call site via
3477/// the narrower [`crate::DepError::FonteRepoEmpty`] variant — the same
3478/// empty-first cascade [`is_dns_1123_label`], [`is_gateway_api_http_path`],
3479/// [`is_wit_world_ref`], [`is_nats_subject`], [`is_wasi_keyvalue_slot`],
3480/// [`is_git_ref_name`], and [`is_git_oid`] all carry.
3481///
3482/// Lifted as the seventh value-shape primitive in this module, peer with
3483/// [`is_git_ref_name`] (the `:fonte :tag` / `:fonte :branch` refname-
3484/// shaped axes) and [`is_git_oid`] (the `:fonte :rev` commit-OID axis) —
3485/// together they bracket the typed `:fonte` slot end-to-end: the
3486/// `:repo` URL axis (gate here), the refname-pin axes (gate via
3487/// `is_git_ref_name`), the OID-pin axis (gate via `is_git_oid`). Every
3488/// validated `:fonte (:tipo git …)` past `DepSource::validate` is
3489/// guaranteed-acceptable by the caixa-resolver's `git clone`/`git
3490/// fetch`/`git checkout` invocations, structurally — the parser-of-
3491/// record divergence the prior trajectory closed on the pin axes is
3492/// now closed on the last unsealed `:fonte` axis.
3493///
3494/// # Errors
3495///
3496/// Returns the parser-shaped reason naming the specific violation
3497/// (length / leading-`-` / whitespace / control-char / non-ASCII /
3498/// fragment-`#` / query-`?` / backslash-`\` / template-`{`-or-`}` /
3499/// shell-redirection-`<`-or-`>` / shell-command-substitution-backtick /
3500/// missing-`:` separator / leading-`:`), without wrapping in any error
3501/// variant — every caller maps the same `String` into its own typed
3502/// `*Invalid { axis, reason }` enum variant.
3503#[allow(
3504    clippy::too_many_lines,
3505    reason = "the per-byte rejection cascade is structurally flat by design — \
3506              every arm carries its own self-locating diagnostic with the offending \
3507              byte named verbatim plus the canonical paste-from-shape footgun the \
3508              gate closes, so collapsing onto a single shared `for &b in …` loop \
3509              would regress the per-arm `feira lint` consumer surface — peer with \
3510              the `clippy::too_many_lines` allow on `DepSource::validate_caminho` \
3511              (caixa-core/src/dep.rs:323) on the same cascade-shape rationale"
3512)]
3513pub fn is_git_repo_url(s: &str) -> Result<(), String> {
3514    if s.is_empty() {
3515        return Err("must not be empty".to_string());
3516    }
3517    if s.len() > GIT_REPO_URL_MAX_LEN {
3518        return Err(format!(
3519            "exceeds git repo URL max length of {GIT_REPO_URL_MAX_LEN} bytes \
3520             (got {} bytes; legitimate `github:org/repo` shorthands and \
3521             `https://…` / `ssh://…` / `git://…` / `file://…` URLs rarely \
3522             exceed ~128 bytes — this length suggests a paste-from-binary or \
3523             multi-line blob landed in the `:repo` slot)",
3524            s.len()
3525        ));
3526    }
3527    if s.starts_with('-') {
3528        return Err(
3529            "must not start with `-` (the canonical CLI-argument-injection \
3530             footgun — `git clone <repo>` interprets a leading `-` as a CLI \
3531             flag, so a `-upload-pack=…` / `--config=…` value escapes the \
3532             subprocess argument boundary; use a scheme prefix like \
3533             `github:org/repo`, `https://host/path`, `ssh://[user@]host/path`, \
3534             `git://host/path`, `git@host:path`, or `file:///path` for the \
3535             intended source)"
3536                .to_string(),
3537        );
3538    }
3539    for &b in s.as_bytes() {
3540        if b == b' ' || b == b'\t' {
3541            return Err(format!(
3542                "must not contain whitespace character {ch:?} (git repo URLs \
3543                 are single tokens with no whitespace — a trailing space in a \
3544                 `:repo` value is the canonical paste-from-doc footgun, \
3545                 silently breaking `git clone '<value> '` at clone time)",
3546                ch = b as char
3547            ));
3548        }
3549        if b < 0x20 || b == 0x7F {
3550            return Err(format!(
3551                "must not contain control character 0x{b:02x} (git repo URLs \
3552                 are printable ASCII; `\\r` / `\\n` are the canonical paste-\
3553                 from-multiline-doc footgun and break git's URL parser at \
3554                 every porcelain entry point, plus CRLF at the URL boundary \
3555                 is a class of subprocess-arg injection)"
3556            ));
3557        }
3558        if b >= 0x80 {
3559            return Err(format!(
3560                "must not contain non-ASCII byte 0x{b:02x} (IDN hosts must be \
3561                 pre-encoded as Punycode `xn--…`; raw non-ASCII silently \
3562                 breaks at git's URL parser and round-trips inconsistently \
3563                 across NFC/NFD normalization on APFS / case-folding \
3564                 filesystems)"
3565            ));
3566        }
3567        if b == b'#' {
3568            return Err("must not contain `#` (RFC 3986 §3.5 URL fragment \
3569                 identifier; libcurl's URL parser — the layer `git \
3570                 clone <https-url>` invokes — strips the `#fragment` \
3571                 tail before opening the transport, so the byte rides \
3572                 verbatim into the lacre's per-dep content-address but \
3573                 is silently dropped on the wire, defeating the \
3574                 THEORY.md §V.2 render-determinism contract: two \
3575                 authors whose `:repo` values differ only in their \
3576                 fragment anchor (`#readme` vs `#L42`) resolve to the \
3577                 byte-identical upstream `git clone` but lock to two \
3578                 distinct BLAKE3 closures. The canonical \
3579                 paste-from-browser-address-bar footgun (every web URL \
3580                 to a README section / line-permalink carries one), \
3581                 and the canonical \"I confused the Nix flake-ref \
3582                 idiom (`github:foo/bar#packageName`) with the bare \
3583                 git `:repo` shape\" footgun — `:repo` is a git URL, \
3584                 not a Nix flake reference, so the `#`-suffix is \
3585                 structurally meaningless on this axis. Drop the \
3586                 `#fragment` tail; pin the ref via the typed `:tag` / \
3587                 `:branch` / `:rev` slot instead)"
3588                .to_string());
3589        }
3590        if b == b'?' {
3591            return Err("must not contain `?` (RFC 3986 §3.4 URL query \
3592                 component; every documented `:fonte :repo` shape \
3593                 (`github:org/repo` shorthand, `https://…` / \
3594                 `ssh://…` / `git://…` / `file://…` URL schemes, \
3595                 `git@host:path` scp-style SSH) carries none. GitHub / \
3596                 GitLab / Bitbucket all silently ignore the `?query` \
3597                 tail on a repo URL and serve the same repo \
3598                 regardless, so the byte rides verbatim into the \
3599                 lacre's per-dep content-address but is silently \
3600                 masked at the wire — two authors whose `:repo` \
3601                 values differ only in their query tail \
3602                 (`?tab=readme-ov-file` vs `?utm_source=twitter`) \
3603                 resolve to the byte-identical upstream `git clone` \
3604                 but lock to two distinct BLAKE3 closures, defeating \
3605                 the THEORY.md §V.2 render-determinism contract on \
3606                 the same axis the fragment-`#` arm closes. The \
3607                 Smart-HTTP transport (the layer \
3608                 `git clone <https-url>` uses) additionally appends \
3609                 its own `?service=git-upload-pack` query internally; \
3610                 an author-supplied `?` byte collides with that \
3611                 internal axis at every git porcelain entry-point. \
3612                 The canonical paste-from-browser-address-bar \
3613                 footgun (`?tab=readme-ov-file` GitHub-tab deep-link, \
3614                 `?ref=main` GitHub-tree-URL parameter, \
3615                 `?utm_source=…` campaign-tracker every social-share / \
3616                 newsletter / Slack-unfurl appends). Drop the \
3617                 `?query` tail; pin the ref via the typed `:tag` / \
3618                 `:branch` / `:rev` slot instead)"
3619                .to_string());
3620        }
3621        if b == b'\\' {
3622            return Err("must not contain `\\` (RFC 3986 §3.3 reserves \
3623                 `/` as the URL path-segment separator; no URL grammar \
3624                 admits `\\`. Every documented `:fonte :repo` shape \
3625                 (`github:org/repo` shorthand, `https://…` / \
3626                 `ssh://…` / `git://…` / `file://…` URL schemes, \
3627                 `git@host:path` scp-style SSH) uses `/` as the path \
3628                 separator. The canonical Windows-path-confusion \
3629                 footgun: an author pastes `file:///C:\\Users\\me\\repo` \
3630                 from a Windows Explorer address bar / PowerShell \
3631                 `Get-Location` output, `https://github.com\\foo\\bar` \
3632                 after a Win32 shell mangled the slashes, or the bare \
3633                 Windows-rooted path `C:\\repo` into a slot expecting a \
3634                 `file://` URL. libcurl's URL parser (the layer \
3635                 `git clone <https-url>` invokes) silently translates \
3636                 `\\` to `/` on some platforms and refuses it on others, \
3637                 so the byte rides verbatim into the lacre's per-dep \
3638                 content-address but is silently rewritten or rejected \
3639                 at the wire, defeating the THEORY.md §V.2 render-\
3640                 determinism contract on the same axis the fragment-`#` \
3641                 and query-`?` arms close. The peer \
3642                 `DepError::FonteCaminhoBackslash` arm (commit 3a4e1d7) \
3643                 closes the same byte on the sibling `:fonte :caminho` \
3644                 path-fonte axis; this arm closes the URL-grammar axis. \
3645                 Drop the `\\` — use `/` for URL path separators, or \
3646                 author the `file:///C:/path` form with forward slashes \
3647                 (the canonical RFC 8089 file-URI shape on Windows-\
3648                 rooted paths))"
3649                .to_string());
3650        }
3651        if b == b'{' || b == b'}' {
3652            return Err(format!(
3653                "must not contain `{ch}` (RFC 3986 §2 excludes `{{` / `}}` \
3654                 from URL syntax — they sit in the 'delims' / 'unwise' \
3655                 byte set every URL parser is required to refuse or \
3656                 percent-encode; RFC 6570 reserves the matched pair for \
3657                 URI Template placeholders (the canonical \
3658                 `https://{{host}}/{{org}}/{{repo}}` substitution shape \
3659                 every OpenAPI / Swagger / Postman / GitHub Octokit \
3660                 client library / Helm chart-URL fragment carries). The \
3661                 canonical 'I forgot to resolve the template \
3662                 placeholder' footgun: an author pastes \
3663                 `:repo \"https://github.com/{{org}}/{{repo}}\"` from a \
3664                 README's quick-start snippet, an OpenAPI spec's \
3665                 `servers:` URL, a Helm chart's `home:` template, or \
3666                 the Mustache / Handlebars `{{{{org}}}}/{{{{repo}}}}` \
3667                 doubled-brace substitution form every CI / IaC \
3668                 templating engine emits, expecting the substrate to \
3669                 resolve the placeholder downstream. libcurl percent-\
3670                 encodes `{{` / `}}` to `%7B` / `%7D` on the wire (so \
3671                 the byte round-trips inconsistently between the \
3672                 lacre's per-dep content-address and the resolver's \
3673                 `git clone <repo>` invocation, defeating the THEORY.md \
3674                 §V.2 render-determinism contract on the same axis the \
3675                 fragment-`#`, query-`?`, and backslash-`\\` arms close) \
3676                 while every git porcelain entry-point fetches a \
3677                 nonexistent literal-`{{placeholder}}`-named path far \
3678                 from the source caixa.lisp. Resolve the placeholder at \
3679                 author time — substitute the literal org / repo name \
3680                 (`https://github.com/pleme-io/hello-rio`), or use \
3681                 `:fonte (:tipo path :caminho \"<local-path>\")` for a \
3682                 local workspace dep)",
3683                ch = b as char
3684            ));
3685        }
3686        if b == b'<' || b == b'>' {
3687            return Err(format!(
3688                "must not contain `{ch}` (RFC 3986 §2 excludes `<` / `>` \
3689                 from URL syntax — they sit in the 'delims' / 'unwise' \
3690                 byte set every URL parser is required to refuse or \
3691                 percent-encode, peer with the `{{` / `}}` URI Template \
3692                 arm on the same paragraph of the same RFC. No git URL \
3693                 grammar admits either byte: the `github:org/repo` \
3694                 shorthand carries an alphanumeric / `-` / `_` / `/` \
3695                 alphabet, every `https://` / `ssh://` / `git://` / \
3696                 `file://` URL scheme percent-encodes `<` to `%3C` and \
3697                 `>` to `%3E` on the wire (the WHATWG URL spec's \
3698                 'fragment percent-encode set' canonical mapping every \
3699                 conformant URL parser applies), and the `git@host:path` \
3700                 scp-style SSH shape names a POSIX path component that \
3701                 carries no shell-metachar bytes. Beyond the URL-grammar \
3702                 violation, every POSIX shell (sh / bash / zsh / dash / \
3703                 ksh / fish / nushell) lexes `<` as the input-redirection \
3704                 operator and `>` as the output-redirection operator — \
3705                 a `:repo \"https://github.com/foo/bar>build.log\"` (the \
3706                 canonical 'I pasted a shell pipeline that wrote build \
3707                 output and forgot to trim the redirect' footgun) or \
3708                 `:repo \"<README.md\"` (the symmetric input-redirection \
3709                 paste idiom every doc-quick-start `git clone <…>` line \
3710                 footnotes) is the canonical paste-from-shell-prompt \
3711                 footgun the typed slot's accepted set must exclude. The \
3712                 byte rides verbatim into the lacre's per-dep content-\
3713                 address (`conteudo: format!(\"git:{{repo}}\")` peer of \
3714                 the path-axis embedding at caixa-resolver/src/resolve.rs:189) \
3715                 and into the resolver's `git clone <repo>` \
3716                 (caixa-resolver/src/git.rs:21) subprocess invocation, \
3717                 where libcurl's URL parser percent-encodes the byte on \
3718                 the wire — so two authors whose `:repo` values differ \
3719                 only in their `<`/`>` presence (one paste-trimmed the \
3720                 redirect tail, the other didn't) resolve to the byte-\
3721                 identical upstream `git clone` but lock to two distinct \
3722                 BLAKE3 closures, defeating the THEORY.md §V.2 render-\
3723                 determinism contract on the same axis the fragment-`#`, \
3724                 query-`?`, backslash-`\\`, and template-`{{` / `}}` arms \
3725                 close. The peer `:fonte :caminho` axis (e457141) closes \
3726                 the same `<` / `>` byte under the shell-redirection \
3727                 banner via `DepError::FonteCaminhoShellRedirection`; the \
3728                 peer `:entrada :paths` axis closes the same bytes as part \
3729                 of `is_gateway_api_http_path`'s eleven-byte RFC-3986-\
3730                 reserved set; the peer `:fonte :tag` / `:fonte :branch` \
3731                 axes (e70d213) close the same bytes as part of \
3732                 `is_git_ref_name`'s shell-metachar-injection cascade. \
3733                 The `:repo` URL axis was the last typed git-source \
3734                 surface still admitting these two bytes; this arm closes \
3735                 the gap so the substrate-wide 'no shell-redirection / \
3736                 RFC-3986-unwise byte anywhere in a typed git-source slot' \
3737                 invariant is now structurally consistent across every \
3738                 git-source-shaped typed surface. Drop the `<` / `>` tail \
3739                 — pin the ref via the typed `:tag` / `:branch` / `:rev` \
3740                 slot, or use `:fonte (:tipo path :caminho \"<local-path>\")` \
3741                 for a local workspace dep)",
3742                ch = b as char
3743            ));
3744        }
3745        if b == b'`' {
3746            return Err(
3747                "must not contain `` ` `` (RFC 3986 §2 lists the backtick byte \
3748                 in the 'delims' / 'unwise' set every URL parser is required \
3749                 to refuse or percent-encode, peer with the `<` / `>` \
3750                 shell-redirection arm on the same paragraph of the same RFC. \
3751                 No git URL grammar admits the byte: the `github:org/repo` \
3752                 shorthand carries an alphanumeric / `-` / `_` / `/` alphabet, \
3753                 every `https://` / `ssh://` / `git://` / `file://` URL scheme \
3754                 percent-encodes `` ` `` to `%60` on the wire (the WHATWG URL \
3755                 spec's 'fragment percent-encode set' canonical mapping every \
3756                 conformant URL parser applies), and the `git@host:path` \
3757                 scp-style SSH shape names a POSIX path component that \
3758                 carries no shell-metachar bytes. Beyond the URL-grammar \
3759                 violation, every POSIX shell (sh / bash / zsh / dash / ksh / \
3760                 fish) lexes the backtick as the legacy command-substitution \
3761                 operator — `` `<cmd>` `` runs `<cmd>` in a subshell and \
3762                 substitutes its stdout, the canonical RCE-class injection \
3763                 vector when a string lands in a shell context. A `:repo \
3764                 \"https://github.com/foo/`whoami`/bar\"` (the canonical \
3765                 paste-from-shell-prompt footgun where the author copies a \
3766                 backtick-templated URL from a doc / README quick-start \
3767                 snippet that expected the substrate to substitute the value \
3768                 downstream) or the symmetric `:repo \"`git config user.name`\"` \
3769                 (the dynamic-config-substitution paste idiom every \
3770                 dev-environment-setup script footnotes) is the canonical \
3771                 paste-from-shell-prompt footgun the typed slot's accepted \
3772                 set must exclude. The byte rides verbatim into the lacre's \
3773                 per-dep content-address (`conteudo: format!(\"git:{repo}\")` \
3774                 peer of the path-axis embedding at \
3775                 caixa-resolver/src/resolve.rs) and into the resolver's `git \
3776                 clone <repo>` (caixa-resolver/src/git.rs) subprocess \
3777                 invocation, where libcurl's URL parser percent-encodes the \
3778                 byte on the wire — so two authors whose `:repo` values \
3779                 differ only in their backtick presence (one paste-trimmed \
3780                 the substitution wrapper, the other didn't) resolve to the \
3781                 byte-identical upstream `git clone` but lock to two distinct \
3782                 BLAKE3 closures, defeating the THEORY.md §V.2 render-\
3783                 determinism contract on the same axis the fragment-`#`, \
3784                 query-`?`, backslash-`\\`, template-`{` / `}`, and \
3785                 shell-redirection-`<` / `>` arms close. The peer `:fonte \
3786                 :caminho` axis (c4d62b3) closes the same byte under the \
3787                 shell-command-substitution banner via \
3788                 `DepError::FonteCaminhoShellCommandSubstitution`; the peer \
3789                 `:entrada :paths` axis closes the same byte as part of \
3790                 `is_gateway_api_http_path`'s eleven-byte RFC-3986-reserved \
3791                 set. Drop the backtick wrapper — substitute the literal \
3792                 value at author time, or use `:fonte (:tipo path :caminho \
3793                 \"<local-path>\")` for a local workspace dep)"
3794                    .to_string(),
3795            );
3796        }
3797        if b == b'|' {
3798            return Err("must not contain `|` (RFC 3986 §2 lists the pipe byte in \
3799                 the 'unwise' set every URL parser is required to refuse or \
3800                 percent-encode, peer with the `{` / `}` URI Template, \
3801                 `<` / `>` shell-redirection, and `` ` `` shell-command-\
3802                 substitution arms on the same paragraph of the same RFC. \
3803                 No git URL grammar admits the byte: the `github:org/repo` \
3804                 shorthand carries an alphanumeric / `-` / `_` / `/` \
3805                 alphabet, every `https://` / `ssh://` / `git://` / \
3806                 `file://` URL scheme percent-encodes `|` to `%7C` on the \
3807                 wire (the WHATWG URL spec's 'fragment percent-encode set' \
3808                 canonical mapping every conformant URL parser applies), \
3809                 and the `git@host:path` scp-style SSH shape names a POSIX \
3810                 path component that carries no shell-metachar bytes. \
3811                 Beyond the URL-grammar violation, every POSIX shell (sh / \
3812                 bash / zsh / dash / ksh / fish / nushell) lexes `|` as the \
3813                 pipe operator — `<cmd1> | <cmd2>` streams cmd1's stdout to \
3814                 cmd2's stdin, the canonical command-chaining injection \
3815                 vector when a string lands in a shell context. A `:repo \
3816                 \"https://github.com/foo/bar|tee build.log\"` (the \
3817                 canonical 'I pasted a shell pipeline that tee'd build \
3818                 output and forgot to trim the pipe tail' footgun) or \
3819                 `:repo \"github:p/x|cat\"` (the symmetric paste-from-\
3820                 shell-prompt idiom every quick-start `git clone <…> | …` \
3821                 line footnotes) is the canonical paste-from-shell-prompt \
3822                 footgun the typed slot's accepted set must exclude. The \
3823                 byte rides verbatim into the lacre's per-dep content-\
3824                 address (`conteudo: format!(\"git:{repo}\")` peer of the \
3825                 path-axis embedding at caixa-resolver/src/resolve.rs) and \
3826                 into the resolver's `git clone <repo>` \
3827                 (caixa-resolver/src/git.rs) subprocess invocation, where \
3828                 libcurl's URL parser percent-encodes the byte on the wire \
3829                 — so two authors whose `:repo` values differ only in \
3830                 their pipe presence (one paste-trimmed the pipeline tail, \
3831                 the other didn't) resolve to the byte-identical upstream \
3832                 `git clone` but lock to two distinct BLAKE3 closures, \
3833                 defeating the THEORY.md §V.2 render-determinism contract \
3834                 on the same axis the fragment-`#`, query-`?`, backslash-\
3835                 `\\`, template-`{` / `}`, shell-redirection-`<` / `>`, \
3836                 and backtick-`` ` `` arms close. The peer `:fonte \
3837                 :caminho` axis (124106f) closes the same byte under the \
3838                 shell-pipe banner via `DepError::FonteCaminhoShellPipe`; \
3839                 the peer `:entrada :paths` axis closes the same byte as \
3840                 part of `is_gateway_api_http_path`'s eleven-byte \
3841                 RFC-3986-reserved set; the peer `:fonte :tag` / `:fonte \
3842                 :branch` axes close the same byte as part of \
3843                 `is_git_ref_name`'s shell-metachar-injection cascade. \
3844                 Drop the pipe tail — substitute the literal value at \
3845                 author time, or use `:fonte (:tipo path :caminho \
3846                 \"<local-path>\")` for a local workspace dep)"
3847                .to_string());
3848        }
3849        if b == b';' {
3850            return Err("must not contain `;` (RFC 3986 §2 lists the semicolon \
3851                 byte in the 'sub-delims' / reserved set every URL parser is \
3852                 required to percent-encode at the path-segment boundary, peer \
3853                 with the `{` / `}` URI Template, `<` / `>` shell-redirection, \
3854                 `` ` `` shell-command-substitution, and `|` shell-pipe arms on \
3855                 the same paragraph of the same RFC. No git URL grammar admits \
3856                 the byte: the `github:org/repo` shorthand carries an \
3857                 alphanumeric / `-` / `_` / `/` alphabet, every `https://` / \
3858                 `ssh://` / `git://` / `file://` URL scheme percent-encodes `;` \
3859                 to `%3B` on the wire (the WHATWG URL spec's 'fragment percent-\
3860                 encode set' canonical mapping every conformant URL parser \
3861                 applies), and the `git@host:path` scp-style SSH shape names a \
3862                 POSIX path component that carries no shell-metachar bytes. \
3863                 Beyond the URL-grammar violation, every POSIX shell (sh / \
3864                 bash / zsh / dash / ksh / fish / nushell) lexes `;` as the \
3865                 sequential-command terminator — `<cmd1>; <cmd2>` fires `<cmd2>` \
3866                 regardless of `<cmd1>`'s exit status, the canonical \
3867                 command-chaining injection vector when a string lands in a \
3868                 shell context. A `:repo \
3869                 \"https://github.com/foo/bar; rm -rf build\"` (the canonical \
3870                 'I pasted a shell one-liner that chained a cleanup tail after \
3871                 the URL and forgot to trim the `; <cmd>` tail' footgun) or \
3872                 `:repo \"github:p/x;;y\"` (the symmetric paste-from-POSIX-\
3873                 `case`-arm `;;` terminator idiom every shell-snippet footnotes) \
3874                 is the canonical paste-from-shell-prompt footgun the typed \
3875                 slot's accepted set must exclude. The byte rides verbatim into \
3876                 the lacre's per-dep content-address (`conteudo: \
3877                 format!(\"git:{repo}\")` peer of the path-axis embedding at \
3878                 caixa-resolver/src/resolve.rs) and into the resolver's `git \
3879                 clone <repo>` (caixa-resolver/src/git.rs) subprocess \
3880                 invocation, where libcurl's URL parser percent-encodes the \
3881                 byte on the wire — so two authors whose `:repo` values differ \
3882                 only in their semicolon presence (one paste-trimmed the \
3883                 sequential-command tail, the other didn't) resolve to the \
3884                 byte-identical upstream `git clone` but lock to two distinct \
3885                 BLAKE3 closures, defeating the THEORY.md §V.2 render-\
3886                 determinism contract on the same axis the fragment-`#`, \
3887                 query-`?`, backslash-`\\`, template-`{` / `}`, \
3888                 shell-redirection-`<` / `>`, backtick-`` ` ``, and \
3889                 shell-pipe-`|` arms close. The peer `:fonte :caminho` axis \
3890                 (05c358e) closes the same byte under the shell-command-\
3891                 separator banner via `DepError::FonteCaminhoShellSemicolon`; \
3892                 the peer `:entrada :paths` axis closes the same byte as part \
3893                 of `is_gateway_api_http_path`'s eleven-byte RFC-3986-reserved \
3894                 set; the peer `:fonte :tag` / `:fonte :branch` axes close the \
3895                 same byte as part of `is_git_ref_name`'s shell-metachar-\
3896                 injection cascade. Drop the `;` tail — substitute the literal \
3897                 value at author time, or use `:fonte (:tipo path :caminho \
3898                 \"<local-path>\")` for a local workspace dep)"
3899                .to_string());
3900        }
3901        if b == b'&' {
3902            return Err("must not contain `&` (RFC 3986 §2 lists the ampersand \
3903                 byte in the 'sub-delims' / reserved set every URL parser is \
3904                 required to percent-encode at the path-segment boundary, peer \
3905                 with the `{` / `}` URI Template, `<` / `>` shell-redirection, \
3906                 `` ` `` shell-command-substitution, `|` shell-pipe, and `;` \
3907                 shell-command-separator arms on the same paragraph of the same \
3908                 RFC. The byte is also the canonical RFC 3986 §3.4 URL query \
3909                 `key=value` pair separator (`?a=1&b=2`), but the prior `?` arm \
3910                 already excludes any `?query` tail on a `:repo` value — every \
3911                 documented `:fonte :repo` shape (`github:org/repo` shorthand, \
3912                 `https://…` / `ssh://…` / `git://…` / `file://…` URL schemes, \
3913                 `git@host:path` scp-style SSH) carries no query component, so \
3914                 the `&` byte cannot appear in a legitimate query position past \
3915                 the `?` gate either. Every `https://` / `ssh://` / `git://` / \
3916                 `file://` URL scheme percent-encodes `&` to `%26` on the wire \
3917                 (the WHATWG URL spec's 'fragment percent-encode set' canonical \
3918                 mapping every conformant URL parser applies), and the \
3919                 `git@host:path` scp-style SSH shape names a POSIX path \
3920                 component that carries no shell-metachar bytes. Beyond the \
3921                 URL-grammar violation, every interactive shell (bash / zsh / \
3922                 fish / nushell) lexes `&` two ways: single `&` as the \
3923                 background-task terminator that detaches the prior command \
3924                 into the background and returns control to the prompt \
3925                 immediately (the canonical `cmd &` idiom every long-running \
3926                 pipeline uses), and double `&&` as the logical-AND list \
3927                 operator that fires the next command only if the prior \
3928                 command succeeded (the canonical `make && make install` idiom \
3929                 every build script carries). A `:repo \
3930                 \"https://github.com/foo/bar & sleep 1\"` (the canonical \
3931                 'I pasted a `git clone <url> & sleep 1` background-launch \
3932                 one-liner and forgot to trim the `& <cmd>` tail' footgun) or \
3933                 `:repo \"github:p/x && echo done\"` (the symmetric \
3934                 paste-from-shell-prompt `cd path && cmd` build-chain idiom \
3935                 every quick-start `git clone <…> && cd <…>` line footnotes) \
3936                 is the canonical paste-from-shell-prompt footgun the typed \
3937                 slot's accepted set must exclude. The byte rides verbatim \
3938                 into the lacre's per-dep content-address (`conteudo: \
3939                 format!(\"git:{repo}\")` peer of the path-axis embedding at \
3940                 caixa-resolver/src/resolve.rs) and into the resolver's `git \
3941                 clone <repo>` (caixa-resolver/src/git.rs) subprocess \
3942                 invocation, where libcurl's URL parser percent-encodes the \
3943                 byte on the wire — so two authors whose `:repo` values \
3944                 differ only in their ampersand presence (one paste-trimmed \
3945                 the background-launch tail, the other didn't) resolve to \
3946                 the byte-identical upstream `git clone` but lock to two \
3947                 distinct BLAKE3 closures, defeating the THEORY.md §V.2 \
3948                 render-determinism contract on the same axis the \
3949                 fragment-`#`, query-`?`, backslash-`\\`, template-`{` / `}`, \
3950                 shell-redirection-`<` / `>`, backtick-`` ` ``, shell-pipe-`|`, \
3951                 and shell-command-separator-`;` arms close. The peer `:fonte \
3952                 :caminho` axis (e12e4f3) closes the same byte under the \
3953                 shell-background / logical-AND banner via \
3954                 `DepError::FonteCaminhoShellBackground`; the peer `:entrada \
3955                 :paths` axis closes the same byte as part of \
3956                 `is_gateway_api_http_path`'s eleven-byte RFC-3986-reserved \
3957                 set; the peer `:fonte :tag` / `:fonte :branch` axes close \
3958                 the same byte as part of `is_git_ref_name`'s shell-metachar-\
3959                 injection cascade. Drop the `&` tail — substitute the literal \
3960                 value at author time, or use `:fonte (:tipo path :caminho \
3961                 \"<local-path>\")` for a local workspace dep)"
3962                .to_string());
3963        }
3964        if b == b'$' {
3965            return Err("must not contain `$` (RFC 3986 §2 lists the dollar \
3966                 byte in the 'sub-delims' / reserved set every URL parser is \
3967                 required to percent-encode at the path-segment boundary, peer \
3968                 with the `;` shell-command-separator and `&` shell-background \
3969                 arms on the same paragraph of the same RFC. No git URL grammar \
3970                 admits the byte: the `github:org/repo` shorthand carries an \
3971                 alphanumeric / `-` / `_` / `/` alphabet, every `https://` / \
3972                 `ssh://` / `git://` / `file://` URL scheme percent-encodes `$` \
3973                 to `%24` on the wire (the WHATWG URL spec's 'fragment percent-\
3974                 encode set' canonical mapping every conformant URL parser \
3975                 applies), and the `git@host:path` scp-style SSH shape names a \
3976                 POSIX path component that carries no shell-metachar bytes. \
3977                 Beyond the URL-grammar violation, every POSIX shell (sh / \
3978                 bash / zsh / dash / ksh / fish / nushell) lexes `$` as the \
3979                 variable-expansion / command-substitution operator: `$<name>` \
3980                 / `${{<name>}}` expands a named variable, `$(<cmd>)` runs a \
3981                 subshell and substitutes its stdout, and `$((<expr>))` \
3982                 evaluates an arithmetic expression — every form is a \
3983                 host-layout / environment-state leak when the byte lands in \
3984                 a value the resolver passes to a shell-spawned subprocess. A \
3985                 `:repo \"https://github.com/$ORG/caixa-teia\"` (the canonical \
3986                 'I pasted a shell one-liner that expanded `$ORG` against the \
3987                 author's local environment and forgot to substitute the \
3988                 literal org name' footgun, identical to the f4efe9c peer arm \
3989                 on the sibling `:caminho` axis that closes `\"$HOME/work/…\"` \
3990                 / `\"${{WORKSPACE}}/…\"`) or `:repo \"github:p/$(whoami)/x\"` \
3991                 (the symmetric paste-from-shell-prompt command-substitution \
3992                 idiom every dev-environment-setup script footnotes) is the \
3993                 canonical paste-from-shell-prompt footgun the typed slot's \
3994                 accepted set must exclude. The byte rides verbatim into the \
3995                 lacre's per-dep content-address (`conteudo: \
3996                 format!(\"git:{repo}\")` peer of the path-axis embedding at \
3997                 caixa-resolver/src/resolve.rs) and into the resolver's `git \
3998                 clone <repo>` (caixa-resolver/src/git.rs) subprocess \
3999                 invocation, where libcurl's URL parser percent-encodes the \
4000                 byte on the wire — so two authors whose `:repo` values \
4001                 differ only in their dollar presence (one substituted the \
4002                 literal value at author time, the other didn't) resolve to \
4003                 the byte-identical upstream `git clone` but lock to two \
4004                 distinct BLAKE3 closures, defeating the THEORY.md §V.2 \
4005                 render-determinism contract on the same axis the \
4006                 fragment-`#`, query-`?`, backslash-`\\`, template-`{` / `}`, \
4007                 shell-redirection-`<` / `>`, backtick-`` ` ``, shell-pipe-`|`, \
4008                 shell-command-separator-`;`, and shell-background-`&` arms \
4009                 close. Beyond the determinism axis, a value like \
4010                 `\"github:$HOME/x\"` is a structural host-layout leak: two \
4011                 authors with the same `:repo` slot but different `$HOME` \
4012                 / `$WORKSPACE` / `$PWD` resolve different upstream URLs at \
4013                 different times — the lacre, far from being a substrate-wide \
4014                 identity, becomes a per-workstation snapshot of the author's \
4015                 shell environment. The peer `:fonte :caminho` axis (f4efe9c) \
4016                 closes the leading-`$` byte under the shell-variable-\
4017                 expansion banner via `DepError::FonteCaminhoVarExpansion`; \
4018                 the peer `:entrada :paths` axis closes the same byte as part \
4019                 of `is_gateway_api_http_path`'s eleven-byte RFC-3986-reserved \
4020                 set; the peer `:fonte :tag` / `:fonte :branch` axes close \
4021                 the same byte as part of `is_git_ref_name`'s shell-metachar-\
4022                 injection cascade — the `:caminho` axis closes only the \
4023                 leading position because absolute / tilde / var arms there \
4024                 are leading-byte sentinels, but the `:repo` URL axis closes \
4025                 the byte anywhere because every per-byte arm on this surface \
4026                 is positional-agnostic (the substitution / leak shapes \
4027                 `\"https://$HOST/p/x\"` and `\"github:p/$(whoami)\"` both \
4028                 carry the byte mid-string). Drop the `$` — substitute the \
4029                 literal value at author time, or use `:fonte (:tipo path \
4030                 :caminho \"<local-path>\")` for a local workspace dep)"
4031                .to_string());
4032        }
4033        if b == b'*' {
4034            return Err("must not contain `*` (RFC 3986 §2 lists the asterisk \
4035                 byte in the 'sub-delims' / reserved set every URL parser is \
4036                 required to percent-encode at the path-segment boundary, peer \
4037                 with the `;` shell-command-separator, `&` shell-background, \
4038                 and `$` shell-variable-expansion arms on the same paragraph of \
4039                 the same RFC. No git URL grammar admits the byte: the \
4040                 `github:org/repo` shorthand carries an alphanumeric / `-` / \
4041                 `_` / `/` alphabet, every `https://` / `ssh://` / `git://` / \
4042                 `file://` URL scheme percent-encodes `*` to `%2A` on the wire \
4043                 (the WHATWG URL spec's 'special-query percent-encode set' \
4044                 canonical mapping every conformant URL parser applies), and \
4045                 the `git@host:path` scp-style SSH shape names a POSIX path \
4046                 component that carries no shell-metachar bytes. Beyond the \
4047                 URL-grammar violation, every POSIX shell (sh / bash / zsh / \
4048                 dash / ksh / fish / nushell) lexes `*` as the \
4049                 pathname-expansion / glob wildcard operator: a single `*` \
4050                 matches any sequence of characters in a path component \
4051                 (including the empty sequence), `**` matches across `/` \
4052                 boundaries under bash's `globstar` shopt, and `foo*` resolves \
4053                 against the cwd-relative filesystem at command-substitution \
4054                 time. Beyond shell glob semantics, git itself lexes `*` as \
4055                 the refspec wildcard operator (`refs/heads/*:refs/remotes/\
4056                 origin/*` — the same byte the peer `is_git_ref_name` \
4057                 predicate refuses on `:fonte :tag` / `:fonte :branch`), so a \
4058                 `:repo` value carrying `*` is structurally ambiguous with \
4059                 every refspec parser the resolver invokes downstream. A \
4060                 `:repo \"https://github.com/pleme-io/caixa-*\"` (the canonical \
4061                 'I pasted a `ls github.com/pleme-io/caixa-*` shell-listing \
4062                 tail and forgot to substitute the literal repo name' \
4063                 footgun, identical to the cf9034b peer arm on the sibling \
4064                 `:caminho` axis that closes `\"../caixa-teia/*\"`) or `:repo \
4065                 \"github:p/*\"` (the symmetric paste-from-shell-prompt \
4066                 glob-expansion idiom every quick-listing one-liner footnotes) \
4067                 is the canonical paste-from-shell-prompt footgun the typed \
4068                 slot's accepted set must exclude. The byte rides verbatim \
4069                 into the lacre's per-dep content-address (`conteudo: \
4070                 format!(\"git:{repo}\")` peer of the path-axis embedding at \
4071                 caixa-resolver/src/resolve.rs) and into the resolver's `git \
4072                 clone <repo>` (caixa-resolver/src/git.rs) subprocess \
4073                 invocation, where libcurl's URL parser percent-encodes the \
4074                 byte on the wire — so two authors whose `:repo` values \
4075                 differ only in their asterisk presence (one substituted the \
4076                 literal repo name at author time, the other didn't) resolve \
4077                 to the byte-identical upstream `git clone` but lock to two \
4078                 distinct BLAKE3 closures, defeating the THEORY.md §V.2 \
4079                 render-determinism contract on the same axis the \
4080                 fragment-`#`, query-`?`, backslash-`\\`, template-`{` / `}`, \
4081                 shell-redirection-`<` / `>`, backtick-`` ` ``, shell-pipe-`|`, \
4082                 shell-command-separator-`;`, shell-background-`&`, and \
4083                 shell-variable-expansion-`$` arms close. The peer `:fonte \
4084                 :caminho` axis (cf9034b) closes the same byte under the \
4085                 shell-glob / pathname-expansion banner via \
4086                 `DepError::FonteCaminhoShellGlob`; the peer `:fonte :tag` / \
4087                 `:fonte :branch` axes close the same byte as part of \
4088                 `is_git_ref_name`'s refspec-wildcard cascade. Drop the `*` — \
4089                 substitute the literal repo name at author time, or use \
4090                 `:fonte (:tipo path :caminho \"<local-path>\")` for a local \
4091                 workspace dep)"
4092                .to_string());
4093        }
4094        if b == b'(' || b == b')' {
4095            return Err(format!(
4096                "must not contain `{ch}` (RFC 3986 §2 excludes `(` / `)` \
4097                 from URL syntax — they sit in the 'sub-delims' / reserved \
4098                 byte set every URL parser is required to percent-encode at \
4099                 the path-segment boundary, peer with the `;` \
4100                 shell-command-separator, `&` shell-background, `$` \
4101                 shell-variable-expansion, and `*` shell-glob arms on the \
4102                 same paragraph of the same RFC. No git URL grammar admits \
4103                 either byte: the `github:org/repo` shorthand carries an \
4104                 alphanumeric / `-` / `_` / `/` alphabet, every `https://` / \
4105                 `ssh://` / `git://` / `file://` URL scheme percent-encodes \
4106                 `(` to `%28` and `)` to `%29` on the wire (the WHATWG URL \
4107                 spec's 'special-query percent-encode set' canonical mapping \
4108                 every conformant URL parser applies), and the \
4109                 `git@host:path` scp-style SSH shape names a POSIX path \
4110                 component that carries no shell-metachar bytes. Beyond the \
4111                 URL-grammar violation, every POSIX shell (sh / bash / zsh / \
4112                 dash / ksh / fish / nushell) lexes `(` / `)` as the \
4113                 subshell-grouping operator: `(<cmd>)` runs `<cmd>` in a \
4114                 child shell with a fresh environment scope (the canonical \
4115                 idiom for sandboxing a `cd` or variable assignment), and \
4116                 `$(<cmd>)` is the modern Bourne command-substitution shape \
4117                 the prior `$` arm closes the leading byte of — the closing \
4118                 `)` byte completes that substitution shape and must be \
4119                 refused on the same axis. The byte pair is additionally the \
4120                 canonical regex-alternation grouping operator (`(foo|bar)`) \
4121                 every doc / README quick-start snippet folds into a paste-\
4122                 from-doc footgun shape, and the bash brace-expansion \
4123                 alternation form (`{{foo,bar}}`) the prior `{{` / `}}` URI \
4124                 Template arm closes on the curly-brace axis routes the \
4125                 same alternation intent through the parenthesis axis on \
4126                 every POSIX-portable script. A `:repo \
4127                 \"https://github.com/(foo|bar)/repo\"` (the canonical 'I \
4128                 pasted a regex-alternation form from a doc / README and \
4129                 forgot to substitute one literal org' footgun) or `:repo \
4130                 \"github:p/x(date)\"` (the symmetric paste-from-shell-\
4131                 prompt subshell-grouping idiom every dynamic-config-\
4132                 substitution one-liner footnotes) is the canonical paste-\
4133                 from-shell-prompt footgun the typed slot's accepted set \
4134                 must exclude. The byte rides verbatim into the lacre's \
4135                 per-dep content-address (`conteudo: \
4136                 format!(\"git:{{repo}}\")` peer of the path-axis embedding \
4137                 at caixa-resolver/src/resolve.rs) and into the resolver's \
4138                 `git clone <repo>` (caixa-resolver/src/git.rs) subprocess \
4139                 invocation, where libcurl's URL parser percent-encodes the \
4140                 byte on the wire — so two authors whose `:repo` values \
4141                 differ only in their parenthesis presence (one paste-\
4142                 trimmed the grouping wrapper, the other didn't) resolve to \
4143                 the byte-identical upstream `git clone` but lock to two \
4144                 distinct BLAKE3 closures, defeating the THEORY.md §V.2 \
4145                 render-determinism contract on the same axis the \
4146                 fragment-`#`, query-`?`, backslash-`\\`, template-`{{` / \
4147                 `}}`, shell-redirection-`<` / `>`, backtick-`` ` ``, \
4148                 shell-pipe-`|`, shell-command-separator-`;`, shell-\
4149                 background-`&`, shell-variable-expansion-`$`, and shell-\
4150                 glob-`*` arms close. Drop the `(` / `)` wrapper — \
4151                 substitute the literal value at author time, or use \
4152                 `:fonte (:tipo path :caminho \"<local-path>\")` for a local \
4153                 workspace dep)",
4154                ch = b as char
4155            ));
4156        }
4157        if b == b'"' {
4158            return Err("must not contain `\"` (RFC 3986 §2 lists the \
4159                 double-quote byte in the 'delims' set every URL parser is \
4160                 required to refuse or percent-encode, peer with the `<` / \
4161                 `>` shell-redirection and `` ` `` shell-command-substitution \
4162                 arms on the same paragraph of the same RFC — the four-byte \
4163                 'delims' subset (`<`, `>`, `\"`, `` ` ``) is the strictest \
4164                 of the §2 reserved classes, every member structurally \
4165                 incompatible with every URL grammar at every position. No \
4166                 git URL grammar admits the byte: the `github:org/repo` \
4167                 shorthand carries an alphanumeric / `-` / `_` / `/` \
4168                 alphabet, every `https://` / `ssh://` / `git://` / \
4169                 `file://` URL scheme percent-encodes `\"` to `%22` on the \
4170                 wire (the WHATWG URL spec's 'C0 control percent-encode \
4171                 set' canonical mapping every conformant URL parser \
4172                 applies), and the `git@host:path` scp-style SSH shape \
4173                 names a POSIX path component that carries no \
4174                 shell-metachar bytes. Beyond the URL-grammar violation, \
4175                 every POSIX shell (sh / bash / zsh / dash / ksh / fish / \
4176                 nushell) lexes `\"` as the double-quote string delimiter — \
4177                 a `\"<text>\"` form suppresses word-splitting and \
4178                 pathname-expansion on `<text>` while still expanding `$`, \
4179                 `` ` ``, and `\\` substitutions inside, the canonical \
4180                 'quote the URL so the shell doesn't re-lex the bytes' \
4181                 idiom every doc / README quick-start snippet wraps the \
4182                 URL argument with. A `:repo \
4183                 \"\\\"https://github.com/pleme-io/caixa-teia\\\"\"` (the \
4184                 canonical paste-from-doc footgun where the author copies \
4185                 `$ git clone \"https://…\"` from a README's quick-start \
4186                 snippet and keeps the surrounding double-quote bytes — \
4187                 the doc quotes the URL so the shell doesn't re-lex \
4188                 metachars inside, but the typed slot is itself a \
4189                 byte-level string parser, not a shell context, so the \
4190                 quote bytes ride into the value verbatim) or `:repo \
4191                 \"github:p/x\\\"tail\"` (the symmetric stray-quote paste \
4192                 idiom every shell-history `git clone …` line footnotes) \
4193                 is the canonical paste-from-shell-quoting footgun the \
4194                 typed slot's accepted set must exclude. The byte rides \
4195                 verbatim into the lacre's per-dep content-address \
4196                 (`conteudo: format!(\"git:{repo}\")` peer of the path-\
4197                 axis embedding at caixa-resolver/src/resolve.rs) and into \
4198                 the resolver's `git clone <repo>` \
4199                 (caixa-resolver/src/git.rs) subprocess invocation, where \
4200                 libcurl's URL parser percent-encodes the byte on the wire \
4201                 — so two authors whose `:repo` values differ only in \
4202                 their double-quote presence (one paste-trimmed the quote \
4203                 wrapper, the other didn't) resolve to the byte-identical \
4204                 upstream `git clone` but lock to two distinct BLAKE3 \
4205                 closures, defeating the THEORY.md §V.2 render-determinism \
4206                 contract on the same axis the fragment-`#`, query-`?`, \
4207                 backslash-`\\`, template-`{` / `}`, shell-redirection-\
4208                 `<` / `>`, backtick-`` ` ``, shell-pipe-`|`, \
4209                 shell-command-separator-`;`, shell-background-`&`, \
4210                 shell-variable-expansion-`$`, shell-glob-`*`, and \
4211                 shell-subshell-grouping-`(` / `)` arms close. The peer \
4212                 `:entrada :paths` axis closes the same byte as part of \
4213                 `is_gateway_api_http_path`'s RFC-3986-reserved set; the \
4214                 `:fonte :tag` / `:fonte :branch` axes close the same byte \
4215                 as part of `is_git_ref_name`'s shell-metachar-injection \
4216                 cascade. Drop the `\"` wrapper — paste only the URL \
4217                 between the quotes, or use `:fonte (:tipo path :caminho \
4218                 \"<local-path>\")` for a local workspace dep)"
4219                .to_string());
4220        }
4221        if b == b'\'' {
4222            return Err("must not contain `'` (RFC 3986 §2.2 lists the \
4223                 single-quote byte in the 'sub-delims' set the URL grammar \
4224                 admits inside a path segment but every WHATWG-conformant \
4225                 special-scheme URL parser percent-encodes inside a query \
4226                 component via the 'special-query percent-encode set' — \
4227                 the peer position the prior `*` / `(` / `)` 'sub-delims' \
4228                 arms close and the partner ASCII string-delimiter to the \
4229                 `\"` 'delims' double-quote byte the prior arm closes. The \
4230                 byte is the second ASCII shell-string-delimiter — `\"` \
4231                 and `'` are the only two ASCII bytes a byte-level string \
4232                 parser sharing a value-shape with a shell argument must \
4233                 refuse on a URL-shaped slot for paste-from-doc safety. No \
4234                 documented `:fonte :repo` shape admits the byte: the \
4235                 `github:org/repo` shorthand carries an alphanumeric / `-` \
4236                 / `_` / `/` alphabet, every `https://` / `ssh://` / \
4237                 `git://` / `file://` URL scheme keeps host / path bodies \
4238                 inside the `unreserved` alphanumeric / `-` / `.` / `_` / \
4239                 `~` set that excludes the byte, and the `git@host:path` \
4240                 scp-style SSH shape names a POSIX path component that \
4241                 carries no shell-metachar bytes. Every POSIX shell (sh / \
4242                 bash / zsh / dash / ksh / fish / nushell) lexes `'` as \
4243                 the single-quote / strong-quote string delimiter — a \
4244                 `'<text>'` form suppresses every form of expansion on \
4245                 `<text>` (no `$`, no `` ` ``, no `\\`, no glob, no \
4246                 word-splitting), the canonical 'strong-quote the URL so \
4247                 the shell doesn't re-lex anything inside' idiom every \
4248                 doc / README quick-start snippet wraps the URL argument \
4249                 with as the stricter, security-conscious alternative to \
4250                 the `\"…\"` weak-quote shape the prior arm closes. A \
4251                 `:repo \"'https://github.com/pleme-io/caixa-teia'\"` (the \
4252                 canonical paste-from-doc-shell-quoting footgun where the \
4253                 author copies `$ git clone 'https://…'` from a README's \
4254                 quick-start snippet and keeps the surrounding strong-\
4255                 quote bytes — the doc strong-quotes the URL so the shell \
4256                 doesn't re-lex any metachars inside, but the typed slot \
4257                 is itself a byte-level string parser, not a shell \
4258                 context, so the quote bytes ride into the value verbatim; \
4259                 the strong-quote idiom is more common than `\"…\"` in \
4260                 security-conscious docs because it forecloses every \
4261                 expansion the weak-quote form still admits inside) or \
4262                 `:repo \"github:p/x'tail\"` (the symmetric stray-quote \
4263                 paste idiom every shell-history `git clone …` line \
4264                 carries when the author paste-trimmed one boundary but \
4265                 not the other) is the canonical paste-from-shell-quoting \
4266                 footgun the typed slot's accepted set must exclude. The \
4267                 byte additionally carries the canonical English-\
4268                 typography apostrophe footgun: an author writes `:repo \
4269                 \"github:p/repo's-fork\"` (the possessive-form paste-\
4270                 from-prose idiom every README / commit-message / chat-\
4271                 thread reference to a repo carries) expecting the \
4272                 substrate to coerce it to a kebab-case slug; the byte \
4273                 rides verbatim into the lacre's per-dep content-address \
4274                 (`conteudo: format!(\"git:{repo}\")` peer of the path-\
4275                 axis embedding at caixa-resolver/src/resolve.rs) and \
4276                 into the resolver's `git clone <repo>` (caixa-resolver/\
4277                 src/git.rs) subprocess invocation, where the upstream \
4278                 host's git porcelain fetches a literal apostrophe-bearing \
4279                 path that no host's repo registry resolves (GitHub / \
4280                 GitLab / Bitbucket / Codeberg / sourcehut all reject `'` \
4281                 in repo slugs at admission time) — so the lacre locks \
4282                 to a `git:github:p/repo's-fork` closure that never \
4283                 resolves at clone time, surfacing as a quoting-confused \
4284                 'remote ref not found' porcelain error far from the \
4285                 source caixa.lisp, defeating the THEORY.md §V.2 render-\
4286                 determinism contract on the same axis the fragment-`#`, \
4287                 query-`?`, backslash-`\\`, template-`{` / `}`, \
4288                 shell-redirection-`<` / `>`, backtick-`` ` ``, \
4289                 shell-pipe-`|`, shell-command-separator-`;`, shell-\
4290                 background-`&`, shell-variable-expansion-`$`, shell-\
4291                 glob-`*`, shell-subshell-grouping-`(` / `)`, and shell-\
4292                 double-quote-`\"` arms close. Together with the prior \
4293                 `\"` arm, this arm closes both ASCII shell-string-\
4294                 delimiter bytes on the typed `:repo` URL axis — every \
4295                 byte the canonical `git clone <repo>` doc-paste idiom \
4296                 wraps the URL argument with is now refused at validate \
4297                 time, before the byte rides into the lacre or the \
4298                 resolver subprocess. Drop the `'` wrapper — paste only \
4299                 the URL between the quotes, or use `:fonte (:tipo path \
4300                 :caminho \"<local-path>\")` for a local workspace dep)"
4301                .to_string());
4302        }
4303        if b == b'!' {
4304            return Err("must not contain `!` (RFC 3986 §2.2 lists the bang byte \
4305                 in the 'sub-delims' set the URL grammar admits inside a \
4306                 path segment but every WHATWG-conformant special-scheme \
4307                 URL parser percent-encodes inside a query component via \
4308                 the 'special-query percent-encode set' — the peer position \
4309                 the prior `*` / `(` / `)` / `'` 'sub-delims' arms close. \
4310                 No documented `:fonte :repo` shape admits the byte: the \
4311                 `github:org/repo` shorthand carries an alphanumeric / `-` \
4312                 / `_` / `/` alphabet, every `https://` / `ssh://` / \
4313                 `git://` / `file://` URL scheme keeps host / path bodies \
4314                 inside the RFC 3986 `unreserved` alphanumeric / `-` / \
4315                 `.` / `_` / `~` set that excludes the byte, and the \
4316                 `git@host:path` scp-style SSH shape names a POSIX path \
4317                 component that carries no shell-metachar bytes. Beyond \
4318                 the URL-grammar question, every interactive POSIX shell \
4319                 with history enabled (bash / ksh / zsh's `bashcompat` \
4320                 mode / csh / tcsh) lexes `!` as the history-expansion \
4321                 prefix — `!command` re-runs the most recent history \
4322                 entry beginning with `command`, `!!` re-runs the prior \
4323                 command verbatim, `!$` substitutes the last word of the \
4324                 prior command, `!:N` substitutes the Nth word, the \
4325                 canonical RCE-class injection vector when a string lands \
4326                 in a shell context with `set -o histexpand` (bash's \
4327                 default for interactive sessions). A `:repo \
4328                 \"https://github.com/foo/bar!sudo\"` (the canonical \
4329                 paste-from-shell-history footgun where the author copies \
4330                 a `git clone <url>!sudo make install` one-liner from a \
4331                 README's quick-start snippet, intending the trailing \
4332                 `!sudo` as a shell-history reference but the typed slot \
4333                 is itself a byte-level string parser, not a shell \
4334                 context, so the bytes ride into the value verbatim) or \
4335                 `:repo \"github:p/repo!!\"` (the symmetric `!!` repeat-\
4336                 prior-command paste idiom every shell-history `git \
4337                 clone …` retry line carries) is the canonical paste-\
4338                 from-shell-history footgun the typed slot's accepted \
4339                 set must exclude. Beyond shell-history, the bang byte \
4340                 carries the canonical English-typography emphasis \
4341                 footgun: an author writes `:repo \
4342                 \"github:p/awesome-repo!\"` (the exclamation-form paste-\
4343                 from-prose idiom every README / chat-thread / commit-\
4344                 message reference to an enthusiastically-named repo \
4345                 carries) expecting the substrate to coerce it to a \
4346                 kebab-case slug; the byte rides verbatim into the \
4347                 lacre's per-dep content-address (`conteudo: \
4348                 format!(\"git:{repo}\")` peer of the path-axis \
4349                 embedding at caixa-resolver/src/resolve.rs) and into \
4350                 the resolver's `git clone <repo>` (caixa-resolver/\
4351                 src/git.rs) subprocess invocation, where the upstream \
4352                 host's git porcelain fetches a literal bang-bearing \
4353                 path that no host's repo registry resolves (GitHub / \
4354                 GitLab / Bitbucket / Codeberg / sourcehut all reject \
4355                 `!` in repo slugs at admission time) — so the lacre \
4356                 locks to a `git:github:p/awesome-repo!` closure that \
4357                 never resolves at clone time, surfacing as a 'remote \
4358                 ref not found' porcelain error far from the source \
4359                 caixa.lisp, defeating the THEORY.md §V.2 render-\
4360                 determinism contract on the same axis the fragment-\
4361                 `#`, query-`?`, backslash-`\\`, template-`{` / `}`, \
4362                 shell-redirection-`<` / `>`, backtick-`` ` ``, shell-\
4363                 pipe-`|`, shell-command-separator-`;`, shell-\
4364                 background-`&`, shell-variable-expansion-`$`, shell-\
4365                 glob-`*`, shell-subshell-grouping-`(` / `)`, shell-\
4366                 double-quote-`\"`, and shell-single-quote-`'` arms \
4367                 close. The peer `:fonte :tag` / `:fonte :branch` axes \
4368                 (`is_git_ref_name`) deliberately admit `!` (git's \
4369                 `check-ref-format` accepts it as a printable byte and \
4370                 the bang carries no refname-grammar meaning); the \
4371                 `:entrada :paths` axis (`is_gateway_api_http_path`) \
4372                 similarly admits it (K8s Gateway API HTTPPathMatch.value \
4373                 OpenAPI regex accepts it). `:repo` is substrate-\
4374                 internal and strictly narrower than its upstream \
4375                 grammar by design, so the divergence is intentional: \
4376                 the shell-history-expansion footgun is real on the \
4377                 typed `:fonte :repo` axis (every `git clone <url>` \
4378                 invocation crosses a shell boundary at the caixa-\
4379                 resolver / `Command::new(\"git\")` subprocess layer) \
4380                 in a way it isn't on the refname / HTTP-path axes that \
4381                 never reach shell context. Drop the trailing `!` — \
4382                 author the bare alphanumeric / `-` / `_` slug, or use \
4383                 `:fonte (:tipo path :caminho \"<local-path>\")` for a \
4384                 local workspace dep)"
4385                .to_string());
4386        }
4387        if b == b',' {
4388            return Err("must not contain `,` (RFC 3986 §2.2 lists the comma byte \
4389                 in the 'sub-delims' set the URL grammar admits inside a \
4390                 path segment but every WHATWG-conformant special-scheme \
4391                 URL parser percent-encodes it inside both the path and \
4392                 query percent-encode sets — the peer position the prior \
4393                 `!` / `*` / `(` / `)` / `'` 'sub-delims' arms close. No \
4394                 documented `:fonte :repo` shape admits the byte: the \
4395                 `github:org/repo` shorthand carries an alphanumeric / `-` \
4396                 / `_` / `/` alphabet, every `https://` / `ssh://` / \
4397                 `git://` / `file://` URL scheme keeps host / path bodies \
4398                 inside the RFC 3986 `unreserved` alphanumeric / `-` / \
4399                 `.` / `_` / `~` set that excludes the byte, and the \
4400                 `git@host:path` scp-style SSH shape names a POSIX path \
4401                 component that carries no list-separator bytes (every \
4402                 forge — GitHub / GitLab / Bitbucket / Codeberg / \
4403                 sourcehut — refuses `,` in repo slugs at admission time). \
4404                 Beyond the URL-grammar question, the comma byte carries \
4405                 the canonical list-separator-belongs-to-list-grammar \
4406                 footgun across every parser-of-record `:fonte :repo` \
4407                 lands in: an author copies a `git clone <urlA>, <urlB>` \
4408                 paste-from-CSV-list one-liner from a multi-repo \
4409                 bootstrap doc (the canonical `git clone --recurse-\
4410                 submodules <a>, <b>, <c>` README-quickstart idiom every \
4411                 mono-repo carries) or pastes a JSON-array literal `[\"a\", \
4412                 \"b\", \"c\"]` from a tooling-config snippet stripped \
4413                 of its brackets, intending the comma to separate \
4414                 multiple repo entries but the typed `:repo` slot names \
4415                 *one* repo (the list-separator belongs to the list \
4416                 grammar of the enclosing `:deps` slot, not to the \
4417                 individual `:repo` value). A `:repo \
4418                 \"github:p/a,github:p/b\"` silently passed every prior \
4419                 arm and rode into the lacre's per-dep content-address \
4420                 (`conteudo: format!(\"git:{repo}\")` peer of the path-\
4421                 axis embedding at caixa-resolver/src/resolve.rs) and \
4422                 into the resolver's `git clone <repo>` (caixa-\
4423                 resolver/src/git.rs) subprocess invocation, where the \
4424                 upstream host's git porcelain fetched a literal comma-\
4425                 bearing path that no host's repo registry resolves — \
4426                 so the lacre locks to a `git:github:p/a,github:p/b` \
4427                 closure that never resolves at clone time, surfacing as \
4428                 a 'remote ref not found' porcelain error far from the \
4429                 source caixa.lisp, defeating the THEORY.md §V.2 render-\
4430                 determinism contract on the same axis the fragment-\
4431                 `#`, query-`?`, backslash-`\\`, template-`{` / `}`, \
4432                 shell-redirection-`<` / `>`, backtick-`` ` ``, shell-\
4433                 pipe-`|`, shell-command-separator-`;`, shell-\
4434                 background-`&`, shell-variable-expansion-`$`, shell-\
4435                 glob-`*`, shell-subshell-grouping-`(` / `)`, shell-\
4436                 double-quote-`\"`, shell-single-quote-`'`, and shell-\
4437                 history-`!` arms close. Beyond the multi-repo paste, \
4438                 the byte carries the canonical English-typography \
4439                 trailing-`,` paste-from-prose footgun: an author writes \
4440                 `:repo \"github:pleme-io/caixa-feira,\"` (the trailing \
4441                 comma every README-prose list-of-projects sentence \
4442                 carries, mistakenly retained when the slug is pasted \
4443                 mid-sentence) expecting the substrate to coerce it to \
4444                 a kebab-case slug; the byte rides verbatim. The peer \
4445                 `:fonte :tag` / `:fonte :branch` axes \
4446                 (`is_git_ref_name`) deliberately admit `,` (git's \
4447                 `check-ref-format` accepts it as a printable byte and \
4448                 the comma carries no refname-grammar meaning); the \
4449                 `:entrada :paths` axis (`is_gateway_api_http_path`) \
4450                 similarly admits it (K8s Gateway API HTTPPathMatch.value \
4451                 OpenAPI regex accepts it). `:repo` is substrate-\
4452                 internal and strictly narrower than its upstream \
4453                 grammar by design, so the divergence is intentional: \
4454                 the list-separator-belongs-to-list-grammar footgun is \
4455                 real on the typed `:fonte :repo` axis (every `:deps` \
4456                 entry names exactly one repo and the comma between \
4457                 entries belongs to the `:deps` list grammar, never to \
4458                 the value) in a way it isn't on the refname / HTTP-\
4459                 path axes whose grammars admit the byte without \
4460                 confusion. Drop the trailing `,` — author the bare \
4461                 alphanumeric / `-` / `_` slug, or split into multiple \
4462                 `:deps` entries to express multiple repos)"
4463                .to_string());
4464        }
4465        if b == b'=' {
4466            return Err("must not contain `=` (RFC 3986 §2.2 lists the equals byte \
4467                 in the 'sub-delims' set — the URL grammar admits the byte \
4468                 inside a path segment, but every WHATWG-conformant special-\
4469                 scheme URL parser percent-encodes it inside a query \
4470                 component via the 'special-query percent-encode set' (the \
4471                 same set the prior `,` / `!` / `*` / `(` / `)` / `'` sub-\
4472                 delims arms close on, peer with the immediately prior `,` \
4473                 arm on the same paragraph of the same RFC). No documented \
4474                 `:fonte :repo` shape admits the byte: the `github:org/repo` \
4475                 shorthand carries an alphanumeric / `-` / `_` / `/` \
4476                 alphabet, every `https://` / `ssh://` / `git://` / \
4477                 `file://` URL scheme keeps host / path bodies inside the \
4478                 RFC 3986 `unreserved` alphanumeric / `-` / `.` / `_` / `~` \
4479                 set that excludes the byte, and the `git@host:path` scp-\
4480                 style SSH shape names a POSIX path component that carries \
4481                 no key-value-separator bytes (every forge — GitHub / \
4482                 GitLab / Bitbucket / Codeberg / sourcehut — refuses `=` in \
4483                 repo slugs at admission time). Beyond the URL-grammar \
4484                 question, the equals byte carries three canonical paste-\
4485                 from-doc footguns the typed `:repo` slot's accepted set \
4486                 must exclude. First, the URL-query key-value-separator \
4487                 paste: an author copies `https://github.com/p/x?ref=main` \
4488                 from a browser address bar / GitHub-tree-URL deep-link / \
4489                 `?utm_source=…` campaign-tracker query string; the prior \
4490                 `?` arm (a68f818) closes the query-prefix byte but every \
4491                 paste-from-doc snippet that lost its `?` prefix (a copy-\
4492                 paste that started mid-query, a shell-pipeline that \
4493                 stripped the leading `?` via `cut -d?`, a docs example \
4494                 that documented the bare `key=value` pairs without the \
4495                 leading `?`) lands a `:repo \"github:p/x ref=main\"` whose \
4496                 `=` byte is now the load-bearing footgun. Second, the \
4497                 shell env-var-assignment paste: every POSIX shell (sh / \
4498                 bash / zsh / dash / ksh / fish) lexes `KEY=VALUE` at the \
4499                 start of a command line as a one-shot env-var assignment \
4500                 scoped to that command (`GIT_TERMINAL_PROMPT=0 git clone \
4501                 <url>` runs `git clone` with the prompt suppressed, \
4502                 `GIT_SSL_NO_VERIFY=1 git clone <url>` skips TLS \
4503                 verification, `HTTPS_PROXY=… git clone <url>` overrides \
4504                 the proxy) — the canonical paste-from-shell-history idiom \
4505                 every git-troubleshooting README documents. An author \
4506                 copies `:repo \"GIT_TERMINAL_PROMPT=0 https://github.com/\
4507                 p/x\"` from a shell-prompt one-liner and the env-var \
4508                 prefix rides verbatim into the value, defeating the \
4509                 substrate's typed `:repo` axis (the env-var prefix \
4510                 belongs to the shell context, not to the URL). Third, the \
4511                 git-CLI-flag paste: every `git` porcelain entry-point \
4512                 accepts `--config <key>=<value>` (`git -c \
4513                 protocol.file.allow=always clone …`, `git -c \
4514                 http.extraHeader=…`) and `git config --get <key>` outputs \
4515                 `<key>=<value>`-shaped lines; an author copies \
4516                 `url=https://github.com/p/x` from `git config --get-all \
4517                 remote.origin.url` output or a `.gitconfig` `[remote \
4518                 \"origin\"] url = https://…` ini-stanza paste and the \
4519                 `url=` prefix rides verbatim into the typed `:repo` slot \
4520                 (the ini-key-prefix belongs to the gitconfig grammar, not \
4521                 to the URL value). A `:repo \"GIT_TERMINAL_PROMPT=0 \
4522                 https://github.com/p/x\"` or `:repo \"url=https://github.\
4523                 com/p/x\"` silently passed every prior arm; the byte rode \
4524                 into the lacre's per-dep content-address (`conteudo: \
4525                 format!(\"git:{repo}\")` peer of the path-axis embedding \
4526                 at caixa-resolver/src/resolve.rs) and into the resolver's \
4527                 `git clone <repo>` (caixa-resolver/src/git.rs) subprocess \
4528                 invocation, where libcurl's URL parser percent-encodes \
4529                 the byte to `%3D` on the wire — so two authors whose \
4530                 `:repo` values differ only in their `=` presence resolve \
4531                 to the byte-identical upstream `git clone` but lock to \
4532                 two distinct BLAKE3 closures, defeating the THEORY.md \
4533                 §V.2 render-determinism contract on the same axis the \
4534                 fragment-`#`, query-`?`, backslash-`\\`, template-`{` / \
4535                 `}`, shell-redirection-`<` / `>`, backtick-`` ` ``, shell-\
4536                 pipe-`|`, shell-command-separator-`;`, shell-background-\
4537                 `&`, shell-variable-expansion-`$`, shell-glob-`*`, shell-\
4538                 subshell-grouping-`(` / `)`, shell-double-quote-`\"`, \
4539                 shell-single-quote-`'`, shell-history-`!`, and list-\
4540                 separator-`,` arms close. The peer `:fonte :tag` / \
4541                 `:fonte :branch` axes (`is_git_ref_name`) deliberately \
4542                 admit `=` (git's `check-ref-format` accepts it as a \
4543                 printable byte and the equals carries no refname-grammar \
4544                 meaning); the `:entrada :paths` axis \
4545                 (`is_gateway_api_http_path`) similarly admits it (K8s \
4546                 Gateway API HTTPPathMatch.value OpenAPI regex accepts \
4547                 it). `:repo` is substrate-internal and strictly narrower \
4548                 than its upstream grammar by design, so the divergence is \
4549                 intentional: the URL-query / shell-env-var-assignment / \
4550                 git-config-ini key-value-separator footgun is real on the \
4551                 typed `:fonte :repo` axis (every `git clone <repo>` \
4552                 invocation crosses a shell boundary at the caixa-\
4553                 resolver subprocess layer, and the lacre's per-dep \
4554                 content-address must be byte-identical to the wire form) \
4555                 in a way it isn't on the refname / HTTP-path axes whose \
4556                 grammars admit the byte without confusion. Drop the `=` — \
4557                 strip the env-var / config-key prefix from the value \
4558                 before the URL, or author the bare alphanumeric / `-` / \
4559                 `_` slug)"
4560                .to_string());
4561        }
4562        if b == b'%' {
4563            return Err(
4564                "must not contain `%` (RFC 3986 §2.1 reserves the percent byte \
4565                 as the URL percent-encoding escape — `%HH` is the \
4566                 mandatory encoding mechanism for every byte outside the \
4567                 `unreserved` alphanumeric / `-` / `.` / `_` / `~` set, \
4568                 and `%` itself must be percent-encoded as `%25` to appear \
4569                 literally inside a URL value, peer with the immediately \
4570                 prior `=` / `,` / `!` / `*` / `(` / `)` / `'` 'sub-delims' \
4571                 arms on the same RFC. No documented `:fonte :repo` shape \
4572                 admits the byte: the `github:org/repo` shorthand carries \
4573                 an alphanumeric / `-` / `_` / `/` alphabet, every \
4574                 `https://` / `ssh://` / `git://` / `file://` URL scheme \
4575                 keeps host / path bodies inside the RFC 3986 `unreserved` \
4576                 set that excludes the byte and every percent-encoded \
4577                 byte (alphanumeric / `-` / `.` / `_` / `~` — no member \
4578                 needs percent-encoding), and the `git@host:path` scp-\
4579                 style SSH shape names a POSIX path component that \
4580                 carries no percent-encoded bytes (every forge — GitHub / \
4581                 GitLab / Bitbucket / Codeberg / sourcehut — refuses `%` \
4582                 in repo slugs at admission time, and IDN host labels \
4583                 must be pre-encoded as Punycode `xn--…` rather than as \
4584                 percent-encoded UTF-8 bytes). Beyond the URL-grammar \
4585                 question, the percent byte is the canonical render-\
4586                 determinism axis-of-non-determinism the typed `:repo` \
4587                 slot must close at the manifest layer. First, the \
4588                 paste-from-browser-address-bar percent-encoded-space \
4589                 footgun: an author copies \
4590                 `https://github.com/p/x%20test` from a browser address \
4591                 bar or a percent-encoded README hyperlink, intending \
4592                 the `%20` as the URL encoding of a literal space; \
4593                 libcurl's URL parser (the layer `git clone <https-url>` \
4594                 invokes) re-percent-encodes the `%` byte to `%25` on \
4595                 the wire (since `%` is reserved as the escape sequence \
4596                 lead-in and must itself be encoded for a literal byte), \
4597                 so the wire request becomes \
4598                 `https://github.com/p/x%2520test` — a different path \
4599                 than the lacre's content-address records, defeating \
4600                 the THEORY.md §V.2 render-determinism contract \
4601                 directly on the encoding-mechanism axis itself (the \
4602                 most direct violation of every prior render-\
4603                 determinism arm — `#`, `?`, `\\`, `{`/`}`, `<`/`>`, \
4604                 `` ` ``, `|`, `;`, `&`, `$`, `*`, `(`/`)`, `\"`, `'`, \
4605                 `!`, `,`, `=` — since `%` is the very encoding step \
4606                 those arms reason about). Second, the lone-percent \
4607                 malformed-escape footgun: an author writes `:repo \
4608                 \"https://github.com/p/x%foo\"` (the `%` not followed \
4609                 by two hex digits) — every WHATWG-conformant URL \
4610                 parser rejects the value at parse time per RFC 3986 \
4611                 §2.1 (`%HH` requires exactly two hex digits to follow), \
4612                 but the byte rides into the lacre's per-dep content-\
4613                 address (`conteudo: format!(\"git:{repo}\")` peer of \
4614                 the path-axis embedding at caixa-resolver/src/resolve.\
4615                 rs) before the resolver subprocess fails far from the \
4616                 source caixa.lisp. Third, the over-encoded path \
4617                 footgun: an author writes `:repo \
4618                 \"https://github.com/p%2Fx\"` intending the `%2F` as \
4619                 the URL encoding of `/`; the GitHub Smart-HTTP \
4620                 transport rejects percent-encoded path-separator bytes \
4621                 in repo URLs (the URL's path-segment grammar is \
4622                 resolved before the percent-decoding pass), but the \
4623                 byte rides verbatim into the lacre and locks a \
4624                 `git:https://github.com/p%2Fx` closure that diverges \
4625                 from the byte-identical `https://github.com/p/x` form \
4626                 every other author authored — two authors whose \
4627                 `:repo` values differ only in their `/` vs `%2F` \
4628                 presence resolve to the byte-identical upstream `git \
4629                 clone` but lock to two distinct BLAKE3 closures, the \
4630                 canonical render-determinism violation. The peer \
4631                 `:fonte :tag` / `:fonte :branch` axes \
4632                 (`is_git_ref_name`) deliberately admit `%` (git's \
4633                 `check-ref-format` accepts it as a printable byte and \
4634                 the percent carries no refname-grammar meaning); the \
4635                 `:entrada :paths` axis (`is_gateway_api_http_path`) \
4636                 similarly admits it (K8s Gateway API \
4637                 HTTPPathMatch.value OpenAPI regex accepts it as a \
4638                 path-segment byte). `:repo` is substrate-internal and \
4639                 strictly narrower than its upstream grammar by design, \
4640                 so the divergence is intentional: the percent-encoding \
4641                 axis is the load-bearing render-determinism axis on \
4642                 the typed `:fonte :repo` slot (every byte the wire \
4643                 differs from the lacre by even a single `%`-escape \
4644                 round-trip violates the substrate's content-addressed-\
4645                 closure contract) in a way it isn't on the refname / \
4646                 HTTP-path axes whose grammars admit the byte without \
4647                 confusion. Drop the `%` — substitute the literal byte \
4648                 directly (the typed slot admits the same `unreserved` \
4649                 byte-set the URL grammar's percent-decoding pass \
4650                 produces, so the percent-encoded form is structurally \
4651                 redundant), or split the encoded value into the typed \
4652                 slot it belongs in (e.g., a host with non-ASCII bytes \
4653                 must be pre-encoded as Punycode `xn--…` rather than \
4654                 percent-encoded UTF-8))"
4655                    .to_string(),
4656            );
4657        }
4658        if b == b'^' {
4659            return Err(
4660                "must not contain `^` (RFC 3986 §2 lists the circumflex byte \
4661                 in the 'unwise' set every URL parser is required to refuse \
4662                 or percent-encode at the path-segment boundary, peer with \
4663                 the `{` / `}` URI Template, `<` / `>` shell-redirection, \
4664                 `` ` `` shell-command-substitution, and `|` shell-pipe arms \
4665                 on the same paragraph of the same RFC — the 'unwise' \
4666                 four-byte subset (`{`, `}`, `|`, `\\`, `^`) is the strictest \
4667                 of the §2 reserved classes, every member structurally \
4668                 incompatible with every URL grammar at every position. No \
4669                 git URL grammar admits the byte: the `github:org/repo` \
4670                 shorthand carries an alphanumeric / `-` / `_` / `/` \
4671                 alphabet, every `https://` / `ssh://` / `git://` / \
4672                 `file://` URL scheme percent-encodes `^` to `%5E` on the \
4673                 wire (the WHATWG URL spec's 'fragment percent-encode set' \
4674                 canonical mapping every conformant URL parser applies), \
4675                 and the `git@host:path` scp-style SSH shape names a POSIX \
4676                 path component that carries no shell-metachar bytes. \
4677                 Beyond the URL-grammar violation, every interactive POSIX \
4678                 shell with history enabled (bash / ksh / zsh's \
4679                 `bashcompat` mode) lexes `^old^new^` as the quick history-\
4680                 substitution shorthand — `^foo^bar` re-runs the most \
4681                 recent history entry with the first `foo` substituted by \
4682                 `bar`, the canonical RCE-class injection vector when a \
4683                 string lands in a shell context with `set -o histexpand` \
4684                 (bash's default for interactive sessions, peer with the \
4685                 `!` history-expansion arm). csh / tcsh lex `^` as the \
4686                 history-substitution prefix (`^old^new` substitutes `old` \
4687                 with `new` in the prior command's first occurrence). Beyond \
4688                 shell history, every regular-expression engine (POSIX BRE \
4689                 / ERE, PCRE, RE2, the rust `regex` crate, JavaScript's \
4690                 `RegExp`) lexes `^` two ways: leading-position `^` anchors \
4691                 the match to the start of the line (the canonical `^foo` \
4692                 anchored-prefix idiom every grep / sed / awk one-liner \
4693                 carries), and inside-class `[^abc]` negates the character \
4694                 class (the canonical exclusion idiom every regex carries). \
4695                 PowerShell (Windows / cross-platform) lexes `^` as the \
4696                 escape character — `cmd ^> file` escapes the redirection \
4697                 operator into a literal byte, the canonical paste-from-\
4698                 PowerShell-prompt footgun on a cross-platform caixa.lisp. \
4699                 A `:repo \"https://github.com/p/x^old^new\"` (the \
4700                 canonical paste-from-shell-history footgun where the \
4701                 author copies a `git clone <url>` line followed by a \
4702                 `^typo^fix` quick-edit-and-rerun shell-history shorthand \
4703                 and forgot to trim the `^...^...` tail) or `:repo \
4704                 \"github:p/^archived\"` (the symmetric regex-anchor / \
4705                 negation paste idiom every doc-quick-start grep-pipeline \
4706                 footnotes) is the canonical paste-from-shell-prompt \
4707                 footgun the typed slot's accepted set must exclude. The \
4708                 byte rides verbatim into the lacre's per-dep content-\
4709                 address (`conteudo: format!(\"git:{repo}\")` peer of the \
4710                 path-axis embedding at caixa-resolver/src/resolve.rs) and \
4711                 into the resolver's `git clone <repo>` \
4712                 (caixa-resolver/src/git.rs) subprocess invocation, where \
4713                 libcurl's URL parser percent-encodes the byte on the wire \
4714                 — so two authors whose `:repo` values differ only in \
4715                 their caret presence (one paste-trimmed the history-\
4716                 substitution shorthand, the other didn't) resolve to the \
4717                 byte-identical upstream `git clone` but lock to two \
4718                 distinct BLAKE3 closures, defeating the THEORY.md §V.2 \
4719                 render-determinism contract on the same axis the \
4720                 fragment-`#`, query-`?`, backslash-`\\`, template-`{` / \
4721                 `}`, shell-redirection-`<` / `>`, backtick-`` ` ``, \
4722                 shell-pipe-`|`, shell-command-separator-`;`, shell-\
4723                 background-`&`, shell-variable-expansion-`$`, shell-glob-\
4724                 `*`, subshell-grouping-`(` / `)`, shell-double-quote-`\"`, \
4725                 shell-single-quote-`'`, history-expansion-`!`, list-\
4726                 separator-`,`, env-var-assignment-`=`, and percent-\
4727                 encoding-`%` arms close. Drop the `^...^...` tail — \
4728                 substitute the literal value at author time, or use \
4729                 `:fonte (:tipo path :caminho \"<local-path>\")` for a \
4730                 local workspace dep)"
4731                    .to_string(),
4732            );
4733        }
4734    }
4735    if s.starts_with(':') {
4736        return Err(
4737            "must not start with `:` (the canonical empty-scheme footgun — \
4738             `:foo` parses as a zero-length scheme that no git porcelain \
4739             entry-point accepts; use a non-empty scheme prefix like \
4740             `github:`, `https://`, `ssh://`, `git://`, `file://`, or the \
4741             `git@host:path` scp-style SSH form)"
4742                .to_string(),
4743        );
4744    }
4745    if !s.contains(':') {
4746        return Err(
4747            "must contain a `:` separator (every documented `:fonte :repo` \
4748             shape carries one: `github:org/repo` shorthand, `https://…` / \
4749             `ssh://…` / `git://…` / `file://…` URL schemes, or \
4750             `git@host:path` scp-style SSH; a bare `org/repo` form is \
4751             ambiguous — `git clone` reads it as a relative filesystem path \
4752             rather than the GitHub-shorthand expansion the author probably \
4753             intended — so prefix it with `github:` for the registry-\
4754             shorthand resolver convention)"
4755                .to_string(),
4756        );
4757    }
4758    Ok(())
4759}
4760
4761/// Practical cap on a `:caracteristicas` (Cargo-feature-name-shaped)
4762/// entry, in bytes. Cargo itself enforces no length cap on feature
4763/// names — its `restricted_names::validate_feature_name` accepts any
4764/// length — but every realistic feature in the Cargo ecosystem is
4765/// well under this bound (`derive` 6, `serde_json` 10, the
4766/// `__private_…` doubled-underscore convention rarely exceeds 32).
4767/// 64 bytes is the substrate's catch-the-paste-from-binary cap on the
4768/// peer trajectory `is_dns_1123_label` (63), `is_wit_world_ref` (128),
4769/// `is_nats_subject` (256), `is_wasi_keyvalue_slot` (512),
4770/// `is_git_ref_name` (255), `is_git_oid` (40/64),
4771/// `is_git_repo_url` (2048) carry: an axis-appropriate ceiling above
4772/// every legitimate authoring shape, tight enough to surface the
4773/// "paste-from-binary" / "multi-line blob landed in a single-token
4774/// slot" footgun at validate time.
4775pub const CARGO_FEATURE_NAME_MAX_LEN: usize = 64;
4776
4777/// Predicate: assert that `s` is a valid Cargo feature name. The
4778/// contract — modeled on Cargo's
4779/// `restricted_names::validate_feature_name` grammar (the parser the
4780/// Cargo resolver routes every `[dependencies.<dep>.features]` entry
4781/// through at `cargo metadata` time), narrowed to the strict ASCII
4782/// subset every realistic feature in the Cargo ecosystem uses:
4783///
4784///   - 1..=[`CARGO_FEATURE_NAME_MAX_LEN`] (64) bytes;
4785///   - first byte: ASCII alphanumeric or `_` (Cargo's parser admits
4786///     Unicode XID-start characters too; pleme-io narrows to the
4787///     ASCII subset for the same reason every peer value-shape
4788///     predicate above narrows — drift between NFC-vs-NFD
4789///     normalization across filesystems silently rewrites the
4790///     feature-key, breaking the lacre's content-addressing
4791///     invariant). Leading `-` / `+` / `.` are explicitly named —
4792///     each is the canonical "I copy-pasted the
4793///     `+optional-feature` enablement form from a Cargo doc" /
4794///     "I confused the dotted-form with feature-name shape"
4795///     footgun the predicate's diagnostic remediation points at;
4796///   - remaining bytes: ASCII alphanumeric, `_`, `-`, `+`, or `.`
4797///     (the Cargo-accepted continuation set). Whitespace, control
4798///     characters, non-ASCII bytes, `/` / `?` / `#` / `,` /
4799///     other punctuation are each surfaced with a self-locating
4800///     reason naming the canonical authoring footgun (multi-token
4801///     blob, CR/LF paste-from-doc, `/` segment-separator confusion
4802///     with namespaced-dep features the predicate's call site
4803///     explicitly does not enable, list-separator-belongs-to-list-
4804///     grammar miscomprehension).
4805///
4806/// Returns the parser-shaped reason on rejection (without wrapping in
4807/// any error variant) so each per-axis caller — [`crate::Dep::validate`]
4808/// for the `:deps`/`:deps-dev :caracteristicas` axis at validate time,
4809/// every future per-feature axis (M4 caixa-resolver's `lacre.lisp`
4810/// resolved-feature-set materializer, the future per-WitContract
4811/// `:caracteristicas`-shaped capability-set axis if WIT worlds grow a
4812/// typed feature toggle, the future per-`UpgradeInstruction` per-
4813/// capability set axis the §V.2 mes-build extension would carry) —
4814/// wraps the same reason in its own typed `*Invalid { <axis>, reason }`
4815/// variant. The reason wording is axis-agnostic ("Cargo feature names
4816/// reject leading `-`") so every call site reading the same diagnostic
4817/// points at the same rule; drift between any two axes' rule
4818/// enforcement is a build error visible at this predicate, not a
4819/// per-renderer "this passed validate but Cargo rejected at metadata
4820/// time" surprise.
4821///
4822/// Empty input is rejected here (defensively) and at each call site
4823/// via the narrower [`crate::DepError::CaracteristicaEmpty`] variant —
4824/// the same empty-first cascade [`is_dns_1123_label`],
4825/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
4826/// [`is_nats_subject`], [`is_wasi_keyvalue_slot`], [`is_git_ref_name`],
4827/// [`is_git_oid`], and [`is_git_repo_url`] all carry.
4828///
4829/// Lifted as a typed substrate-side primitive on the same trajectory
4830/// the peer value-shape predicates already follow — the typed slot's
4831/// valid set matches the downstream consumer's accepted set (here,
4832/// Cargo's TOML-feature-name parser at `cargo metadata` time),
4833/// structurally. The ninth value-shape primitive to land in
4834/// [`crate::render`], closing the typed `:deps`/`:deps-dev` surface
4835/// value-shape trajectory on its last unsealed axis (`:caracteristicas`
4836/// entries; the per-entry `:nome` / `:versao` / `:fonte` axes are
4837/// already routed through their respective shape predicates).
4838///
4839/// # Errors
4840///
4841/// Returns the parser-shaped reason naming the specific violation
4842/// (length / first-byte-class / continuation-byte-class / whitespace /
4843/// control-char / non-ASCII / `/`-segment-separator-confusion /
4844/// `,`-list-separator-confusion), without wrapping in any error
4845/// variant — every caller maps the same `String` into its own typed
4846/// `*Invalid { <axis>, reason }` enum variant.
4847pub fn is_cargo_feature_name(s: &str) -> Result<(), String> {
4848    if s.is_empty() {
4849        return Err("must not be empty".to_string());
4850    }
4851    if s.len() > CARGO_FEATURE_NAME_MAX_LEN {
4852        return Err(format!(
4853            "exceeds Cargo feature name max length of {CARGO_FEATURE_NAME_MAX_LEN} bytes \
4854             (got {} bytes; legitimate Cargo feature names rarely exceed ~24 bytes — \
4855             this length suggests a paste-from-binary or multi-token blob landed in \
4856             the `:caracteristicas` slot)",
4857            s.len()
4858        ));
4859    }
4860    let bytes = s.as_bytes();
4861    let first = bytes[0];
4862    if !(first.is_ascii_alphanumeric() || first == b'_') {
4863        let msg = if first == b'+' {
4864            "must not start with `+` (Cargo's feature-name grammar reserves a leading \
4865             `+` for the activation-syntax inside a `[dependencies.<dep>.features]` \
4866             list — `:caracteristicas` entries name the feature itself, not its \
4867             enablement form; drop the leading `+` and author the bare feature name, \
4868             e.g. `\"http\"` not `\"+http\"`)"
4869                .to_string()
4870        } else if first == b'-' {
4871            "must not start with `-` (Cargo's feature-name grammar rejects a leading \
4872             hyphen — `-` is a legitimate continuation character between alphanumeric \
4873             segments but the canonical CLI-argument-injection / kebab-leak footgun at \
4874             the start; drop the leading `-`, e.g. `\"json\"` not `\"-json\"`)"
4875                .to_string()
4876        } else if first == b'.' {
4877            "must not start with `.` (Cargo's feature-name grammar rejects a leading \
4878             dot; `.` is a legitimate continuation character but the canonical \
4879             leading-dot-as-version-suffix / hidden-file footgun at the start. Drop \
4880             the leading `.`)"
4881                .to_string()
4882        } else if first == b' ' || first == b'\t' {
4883            "must not start with whitespace (Cargo's feature-name grammar rejects \
4884             whitespace anywhere; the leading-whitespace arm is the canonical \
4885             paste-from-aligned-doc footgun)"
4886                .to_string()
4887        } else if first < 0x20 || first == 0x7F {
4888            format!(
4889                "must not start with control character 0x{first:02x} (Cargo's feature-name \
4890                 grammar rejects ASCII control characters; the CR/LF arm is the canonical \
4891                 paste-from-multiline-doc footgun)"
4892            )
4893        } else if first >= 0x80 {
4894            format!(
4895                "must not start with non-ASCII byte 0x{first:02x} (Cargo accepts Unicode \
4896                 XID-start characters but pleme-io narrows to the strict ASCII subset every \
4897                 realistic feature name uses; legitimate features are kebab-case ASCII \
4898                 identifiers like `\"http\"`, `\"json\"`, `\"derive\"`)"
4899            )
4900        } else {
4901            format!(
4902                "must start with an ASCII alphanumeric character or `_`, got {ch:?} \
4903                 (Cargo's `restricted_names::validate_feature_name` rejects feature names \
4904                 whose first character is outside the XID-start + `_` + digit set; \
4905                 pleme-io narrows to the strict ASCII alphanumeric + `_` subset)",
4906                ch = first as char
4907            )
4908        };
4909        return Err(msg);
4910    }
4911    for &b in &bytes[1..] {
4912        let valid = b.is_ascii_alphanumeric() || b == b'_' || b == b'-' || b == b'+' || b == b'.';
4913        if !valid {
4914            let msg = if b == b' ' || b == b'\t' {
4915                format!(
4916                    "must not contain whitespace character {ch:?} (Cargo's feature-name \
4917                     grammar rejects whitespace; feature names are single-token identifiers \
4918                     — use `-` or `_` to separate kebab-case / snake-case segments instead)",
4919                    ch = b as char
4920                )
4921            } else if b == b',' {
4922                "must not contain `,` (the comma separator belongs to the \
4923                 `:caracteristicas` list grammar between entries, not to the feature-name \
4924                 grammar within an entry — split the value into two separate list entries)"
4925                    .to_string()
4926            } else if b == b'/' {
4927                "must not contain `/` (Cargo's `dep/feat` syntax for namespaced-dep \
4928                 features applies inside `[dependencies.<dep>.features]` list entries that \
4929                 already name the parent dep — `:caracteristicas` entries are per-dep \
4930                 already, so the segment separator within a feature name must be `-`, \
4931                 `_`, `+`, or `.`)"
4932                    .to_string()
4933            } else if b == b'?' {
4934                "must not contain `?` (Cargo's feature-name grammar rejects URL-reserved \
4935                 punctuation; use `-`, `_`, `+`, or `.` as a segment separator instead)"
4936                    .to_string()
4937            } else if b == b'#' {
4938                "must not contain `#` (Cargo's feature-name grammar rejects URL-reserved \
4939                 punctuation; use `-`, `_`, `+`, or `.` as a segment separator instead)"
4940                    .to_string()
4941            } else if b < 0x20 || b == 0x7F {
4942                format!(
4943                    "must not contain control character 0x{b:02x} (Cargo's feature-name \
4944                     grammar rejects ASCII control characters; the CR/LF arm is the \
4945                     canonical paste-from-multiline-doc footgun)"
4946                )
4947            } else if b >= 0x80 {
4948                format!(
4949                    "must not contain non-ASCII byte 0x{b:02x} (Cargo accepts Unicode \
4950                     XID-continue characters but pleme-io narrows to the strict ASCII \
4951                     subset every realistic feature name uses; raw non-ASCII silently \
4952                     round-trips inconsistently across NFC/NFD normalization on APFS / \
4953                     case-folding filesystems, breaking the lacre's content-addressing \
4954                     invariant)"
4955                )
4956            } else {
4957                format!(
4958                    "contains invalid character {ch:?} (Cargo's feature-name grammar \
4959                     allows only `[A-Za-z0-9_+\\-.]` after the first character)",
4960                    ch = b as char
4961                )
4962            };
4963            return Err(msg);
4964        }
4965    }
4966    Ok(())
4967}
4968
4969/// Practical cap on a `:licenca` (SPDX-expression-shaped) value, in
4970/// bytes. The SPDX specification places no length cap on expressions
4971/// — the grammar admits arbitrarily-nested composite expressions —
4972/// but every realistic pleme-io fixture stays well under this bound
4973/// (`MIT` 3, `Apache-2.0` 10, `Apache-2.0 OR MIT` 17, the longest
4974/// SPDX dual-license-with-exception shape `Apache-2.0 WITH
4975/// LLVM-exception` 31; a `(MIT OR Apache-2.0) AND BSD-3-Clause AND
4976/// ISC` composite caps near 50). 256 bytes is the substrate's
4977/// catch-the-paste-from-binary cap on the peer trajectory
4978/// `is_dns_1123_label` (63), `is_cargo_feature_name` (64),
4979/// `is_wit_world_ref` (128), `is_nats_subject` (256),
4980/// `is_wasi_keyvalue_slot` (512), `is_git_ref_name` (255),
4981/// `is_git_oid` (40/64), `is_git_repo_url` (2048) carry: an
4982/// axis-appropriate ceiling above every legitimate authoring shape,
4983/// tight enough to surface the "paste-from-license-text" /
4984/// "multi-line license blob landed in the `:licenca` slot" footgun
4985/// at validate time.
4986pub const SPDX_EXPRESSION_MAX_LEN: usize = 256;
4987
4988/// Predicate: assert that `s` is a valid SPDX-expression shape. The
4989/// contract — modeled on the SPDX 2.1 expression grammar
4990/// (`compound-expression = simple-expression | "(" compound-expression
4991/// ")" | compound-expression "WITH" exception-id | compound-expression
4992/// "AND" compound-expression | compound-expression "OR"
4993/// compound-expression`; `simple-expression = license-id | license-id
4994/// "+" | "LicenseRef-" idstring | "DocumentRef-" idstring ":"
4995/// "LicenseRef-" idstring`; `idstring = 1*(ALPHA / DIGIT / "-" /
4996/// ".")`), narrowed to the structural alphabet floor every realistic
4997/// SPDX expression in the wild uses:
4998///
4999///   - 1..=[`SPDX_EXPRESSION_MAX_LEN`] (256) bytes;
5000///   - no leading whitespace (paste-from-aligned-doc footgun);
5001///   - no trailing whitespace (paste-from-doc footgun — every
5002///     downstream SPDX parser splits on exact token boundaries and
5003///     a trailing space breaks the `WITH` / `AND` / `OR` keyword
5004///     match);
5005///   - every byte in the SPDX expression alphabet: ASCII alphanumeric
5006///     plus `.`, `-`, `+`, `(`, `)`, `:` (the `DocumentRef-…:LicenseRef-…`
5007///     separator), and a single ASCII space (token separator). Tabs,
5008///     control characters, non-ASCII bytes, `_` (not in `idstring`),
5009///     `,` (SPDX uses `AND` / `OR` keywords, not comma), `/` (the
5010///     `dual-license/A` colloquial idiom is non-SPDX), and every other
5011///     punctuation byte are each surfaced with a self-locating reason
5012///     naming the canonical authoring footgun.
5013///
5014/// The predicate is a *structural* floor — it enforces the alphabet +
5015/// length the SPDX grammar's character class admits, not the full
5016/// expression-parse (compound-expression nesting, `AND`/`OR`/`WITH`
5017/// keyword placement, parenthesis balance, idstring well-formedness
5018/// per simple-expression production). A future tightening on the
5019/// `:licenca` axis can extend past this shape predicate into a full
5020/// SPDX parser + license-id allowlist (peer with how
5021/// [`is_git_repo_url`] is the structural floor on `:repositorio` and
5022/// a future flake-resolver might tighten the per-URL-scheme arm into
5023/// scheme-specific shape predicates). This gate closes the
5024/// `_`/`,`/`/`/tab/CR/LF/non-ASCII/multi-line-blob footguns
5025/// structurally at the manifest layer; the parser-shape arms remain
5026/// for a follow-up routine once a real SPDX-parser dep is justified.
5027///
5028/// Returns the parser-shaped reason on rejection (without wrapping in
5029/// any error variant) so each per-axis caller —
5030/// [`crate::Caixa::validate_licenca`] for the universal `:licenca`
5031/// axis at validate time, every future per-license axis (a future
5032/// `:fonte :license` per-dep license-pin axis, a future
5033/// per-`UpgradeInstruction` per-component license-compatibility axis,
5034/// a future `Lacre` per-resolved-dep license-closure axis) — wraps the
5035/// same reason in its own typed `*Invalid { <axis>, reason }` variant.
5036/// The reason wording is axis-agnostic ("SPDX expressions reject
5037/// leading whitespace") so every call site reading the same diagnostic
5038/// points at the same rule; drift between any two axes' rule
5039/// enforcement is a build error visible at this predicate, not a
5040/// per-renderer "this passed validate but `helm lint` rejected the
5041/// `Chart.yaml license:` value" surprise.
5042///
5043/// Empty input is rejected here (defensively) and at each call site
5044/// via the narrower [`crate::ManifestError::LicencaEmpty`] variant —
5045/// the same empty-first cascade [`is_dns_1123_label`],
5046/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
5047/// [`is_nats_subject`], [`is_wasi_keyvalue_slot`], [`is_git_ref_name`],
5048/// [`is_git_oid`], [`is_git_repo_url`], and [`is_cargo_feature_name`]
5049/// all carry.
5050///
5051/// Lifted as a typed substrate-side primitive on the same trajectory
5052/// the peer value-shape predicates already follow — the typed slot's
5053/// valid set matches the downstream consumer's accepted set (here,
5054/// the `caixa-helm` chart `README.md` `## License` section + a
5055/// future SPDX-aware Chart.yaml `license:` emitter + the future
5056/// per-resolved-dep license-closure axis a forthcoming `Lacre`
5057/// extension would carry), structurally.
5058///
5059/// # Errors
5060///
5061/// Returns the parser-shaped reason naming the specific violation
5062/// (length / leading-whitespace / trailing-whitespace /
5063/// alphabet-class / tab / control-char / non-ASCII / `_` /
5064/// `,`-list-separator-confusion / `/`-dual-license-idiom), without
5065/// wrapping in any error variant — every caller maps the same
5066/// `String` into its own typed `*Invalid { <axis>, reason }` enum
5067/// variant.
5068pub fn is_spdx_expression_shape(s: &str) -> Result<(), String> {
5069    if s.is_empty() {
5070        return Err("must not be empty".to_string());
5071    }
5072    if s.len() > SPDX_EXPRESSION_MAX_LEN {
5073        return Err(format!(
5074            "exceeds SPDX expression max length of {SPDX_EXPRESSION_MAX_LEN} bytes \
5075             (got {} bytes; realistic SPDX expressions like `\"Apache-2.0 WITH \
5076             LLVM-exception\"` rarely exceed ~64 bytes — this length suggests a \
5077             paste-from-license-text or multi-line blob landed in the `:licenca` \
5078             slot)",
5079            s.len()
5080        ));
5081    }
5082    let bytes = s.as_bytes();
5083    if bytes[0] == b' ' {
5084        return Err(
5085            "must not start with whitespace (SPDX expressions are single tokens \
5086             or token sequences separated by *internal* single ASCII spaces; a \
5087             leading space is the canonical paste-from-aligned-doc footgun and \
5088             breaks every downstream SPDX parser that splits on exact token \
5089             boundaries)"
5090                .to_string(),
5091        );
5092    }
5093    if *bytes.last().expect("non-empty checked above") == b' ' {
5094        return Err(
5095            "must not end with whitespace (SPDX expressions don't terminate with \
5096             trailing whitespace; the trailing-space arm is the canonical \
5097             paste-from-doc footgun that breaks downstream parsers which split \
5098             on exact `AND` / `OR` / `WITH` keyword boundaries)"
5099                .to_string(),
5100        );
5101    }
5102    for &b in bytes {
5103        let valid = b.is_ascii_alphanumeric()
5104            || b == b'.'
5105            || b == b'-'
5106            || b == b'+'
5107            || b == b'('
5108            || b == b')'
5109            || b == b':'
5110            || b == b' ';
5111        if !valid {
5112            let msg = if b == b'\t' {
5113                "must not contain tab character (SPDX expressions use a single \
5114                 ASCII space between tokens — tabs are the canonical \
5115                 paste-from-aligned-doc footgun and break downstream parsers \
5116                 that split on exact `\" \"` boundaries)"
5117                    .to_string()
5118            } else if b < 0x20 || b == 0x7F {
5119                format!(
5120                    "must not contain control character 0x{b:02x} (SPDX \
5121                     expressions are printable ASCII; the CR/LF arm is the \
5122                     canonical paste-from-multiline-doc footgun and lands as a \
5123                     malformed line in the rendered chart `README.md` `## \
5124                     License` section)"
5125                )
5126            } else if b >= 0x80 {
5127                format!(
5128                    "must not contain non-ASCII byte 0x{b:02x} (SPDX identifiers \
5129                     are ASCII per the `idstring = 1*(ALPHA / DIGIT / \"-\" / \
5130                     \".\")` production; raw non-ASCII silently round-trips \
5131                     inconsistently across NFC/NFD normalization on APFS / \
5132                     case-folding filesystems and breaks at every downstream \
5133                     SPDX-aware tool)"
5134                )
5135            } else if b == b'_' {
5136                "must not contain `_` (SPDX `idstring` grammar — license-id, \
5137                 LicenseRef, exception-id — is `1*(ALPHA / DIGIT / \"-\" / \
5138                 \".\")`; `_` is not in the SPDX alphabet, use `-` as the \
5139                 segment separator instead, e.g. `\"Apache-2.0\"` not \
5140                 `\"Apache_2.0\"`)"
5141                    .to_string()
5142            } else if b == b',' {
5143                "must not contain `,` (SPDX expressions compose multiple \
5144                 licenses via the `AND` / `OR` keywords, not the comma \
5145                 separator; e.g. `\"MIT OR Apache-2.0\"` not `\"MIT, \
5146                 Apache-2.0\"`)"
5147                    .to_string()
5148            } else if b == b'/' {
5149                "must not contain `/` (the `dual-license/A` slash form is a \
5150                 non-SPDX colloquial idiom; SPDX uses the `OR` keyword to \
5151                 compose: `\"MIT OR Apache-2.0\"` not `\"MIT/Apache-2.0\"`)"
5152                    .to_string()
5153            } else if b == b';' {
5154                "must not contain `;` (SPDX expressions compose multiple \
5155                 licenses via the `AND` / `OR` keywords, not the semicolon \
5156                 separator; e.g. `\"MIT AND Apache-2.0\"` not `\"MIT; \
5157                 Apache-2.0\"`)"
5158                    .to_string()
5159            } else {
5160                format!(
5161                    "contains invalid character {ch:?} (the SPDX expression \
5162                     alphabet is `[A-Za-z0-9.+\\-():]` plus single ASCII space; \
5163                     license IDs / exception IDs are `idstring` `1*(ALPHA / \
5164                     DIGIT / \"-\" / \".\")`, composition uses `AND` / `OR` / \
5165                     `WITH` keywords + `(`/`)` grouping)",
5166                    ch = b as char
5167                )
5168            };
5169            return Err(msg);
5170        }
5171    }
5172    Ok(())
5173}
5174
5175/// Maximum byte length of a chart-description-shaped string. The
5176/// 512-byte cap is the axis-appropriate ceiling for the free-form
5177/// prose summary the `:descricao` axis carries: every realistic
5178/// chart description in the wild (`"Canonical Rust→wasm32-wasip2
5179/// caixa Servico."`, `"Checkout flow."`, `"AWS provider caixa for
5180/// tatara-lisp"`) sits well under 256 bytes, and the 512-byte cap
5181/// surfaces the "paste-from-doc multi-paragraph blob landed in the
5182/// `:descricao` slot" footgun at validate time. Peer with
5183/// [`WASI_KV_SLOT_MAX_LEN`] (512) on the sibling longer-than-
5184/// identifier axis; tighter than [`GIT_REPO_URL_MAX_LEN`] (2048)
5185/// which carries a different axis-class ceiling, and looser than
5186/// [`SPDX_EXPRESSION_MAX_LEN`] (256) which is the canonical
5187/// short-identifier-class axis.
5188pub const CHART_DESCRIPTION_MAX_LEN: usize = 512;
5189
5190/// Scan `s` for the Unicode bidirectional-override / isolate format
5191/// codepoints UAX #9 names as the structural prerequisite of the
5192/// "Trojan Source" attack class (CVE-2021-42574 / Boucher & Anderson
5193/// 2021): nine codepoints in two contiguous blocks that flip the
5194/// rendered visual order of every following character until a
5195/// matching pop, so a string visible to a human reader and the same
5196/// string consumed by a parser/renderer can disagree on the order of
5197/// its content bytes.
5198///
5199/// The accepted set (rejection list):
5200///
5201///   - U+202A `LRE` LEFT-TO-RIGHT EMBEDDING
5202///   - U+202B `RLE` RIGHT-TO-LEFT EMBEDDING
5203///   - U+202C `PDF` POP DIRECTIONAL FORMATTING
5204///   - U+202D `LRO` LEFT-TO-RIGHT OVERRIDE
5205///   - U+202E `RLO` RIGHT-TO-LEFT OVERRIDE
5206///   - U+2066 `LRI` LEFT-TO-RIGHT ISOLATE
5207///   - U+2067 `RLI` RIGHT-TO-LEFT ISOLATE
5208///   - U+2068 `FSI` FIRST STRONG ISOLATE
5209///   - U+2069 `PDI` POP DIRECTIONAL ISOLATE
5210///
5211/// Returns the first offending codepoint in document order, or
5212/// `None` when `s` carries none of them. Iterates `chars()` once
5213/// (single UTF-8 decode pass, peer of every other UTF-8-aware
5214/// predicate in this module) — the per-predicate caller folds the
5215/// `Some(c)` into its axis-specific reason wording with the
5216/// offending codepoint named verbatim as `U+XXXX`.
5217///
5218/// Lifted as a shared helper rather than inlined into each per-axis
5219/// predicate (the PRIME DIRECTIVE duplication-budget rule —
5220/// THEORY.md §I.3.5: "every recurring shape becomes a generator
5221/// before it becomes a pattern; every pattern becomes a library
5222/// before it becomes duplicated code. The duplication budget is
5223/// zero.") because two predicates ([`is_chart_description_shape`],
5224/// [`is_chart_maintainer_name_shape`]) carry the same UTF-8
5225/// free-form-prose accepted set and would otherwise inline the same
5226/// nine-codepoint match arm verbatim. The third caller — every
5227/// future per-axis free-form-prose surface (a future Aplicacao-
5228/// level `:descricao` summary axis, a future per-`:contratos` edge
5229/// `:descricao` annotation, the future per-`:autores`-email-suffix
5230/// shape gate) — lands as a thin `if let Some(c) =
5231/// find_unicode_bidi_override(s) { … }` wrapper rather than
5232/// re-inlining the same codepoint match.
5233///
5234/// The arm is structurally distinct from the per-byte control-char
5235/// arm `[is_chart_description_shape]` already carries: ASCII control
5236/// bytes (`0x00..=0x1F` plus `0x7F`) are caught at the per-byte
5237/// pass; the bidi codepoints all decode to non-ASCII three-byte
5238/// UTF-8 sequences (`E2 80 AA..=E2 80 AE` for U+202A..=U+202E,
5239/// `E2 81 A6..=E2 81 A9` for U+2066..=U+2069) — every byte ≥ 0x80
5240/// per UTF-8 grammar — that the per-byte non-ASCII pass deliberately
5241/// accepts (Unicode letters, em-dash, arrows are canonical
5242/// `:descricao` shapes). Only the typed codepoint scan catches them.
5243fn find_unicode_bidi_override(s: &str) -> Option<char> {
5244    s.chars().find(|c| {
5245        matches!(
5246            *c,
5247            '\u{202A}'
5248                | '\u{202B}'
5249                | '\u{202C}'
5250                | '\u{202D}'
5251                | '\u{202E}'
5252                | '\u{2066}'
5253                | '\u{2067}'
5254                | '\u{2068}'
5255                | '\u{2069}'
5256        )
5257    })
5258}
5259
5260/// Scan `s` for any of the three non-ASCII Unicode line-break
5261/// codepoints UAX #14 (Unicode Line Breaking Algorithm) and the
5262/// YAML 1.1 §4.1 b-char production both treat as line terminators
5263/// outside the two single-byte ASCII shapes (`\n` LF / `\r` CR) the
5264/// per-byte arm on the calling predicate already closes:
5265///
5266///   - U+0085 `NEL` NEXT LINE
5267///   - U+2028 `LS`  LINE SEPARATOR
5268///   - U+2029 `PS`  PARAGRAPH SEPARATOR
5269///
5270/// YAML 1.2 §5.4 ("Line Break Characters") explicitly retired these
5271/// three from the YAML line-break set per the UTR #20 recommendation,
5272/// so a YAML 1.2-strict parser (the `serde_yaml` / `yaml-rust2` family)
5273/// preserves them as literal codepoints inside the rendered Chart.yaml
5274/// scalar — but YAML 1.1 parsers (go-yaml v2 which Helm v3 / kubectl /
5275/// every Kubernetes client library transitively links, and `ruamel.yaml`
5276/// in compat mode) still treat them as line terminators per the YAML 1.1
5277/// b-char production, so the same `:descricao` / `:autores` value
5278/// authored with an embedded U+2028 parses as a single-line plain-style
5279/// scalar through one downstream consumer and a multi-line block scalar
5280/// through another. The cross-parser line-break disagreement breaks the
5281/// THEORY.md §V.2 render-determinism contract every typed slot carries
5282/// on the same axis the per-byte `\n` / `\r` arms close for ASCII; the
5283/// substrate refuses the three codepoints at validate time so the
5284/// rendered Chart.yaml carries the single-line shape every conformant
5285/// YAML parser agrees on. Independently, every UAX #14 conformant text
5286/// consumer (editors, terminals, web UIs like `helm list` /
5287/// `helm search` / Artifact Hub) breaks the visual line at these
5288/// codepoints regardless of YAML version, so the author's editor view
5289/// of `caixa.lisp` disagrees with the chart-consumer's rendered view
5290/// even when both YAML parsers agree on the byte-level shape.
5291///
5292/// Returns the first offending codepoint in document order, or `None`
5293/// when `s` carries none of them. Iterates `chars()` once (single
5294/// UTF-8 decode pass, peer of [`find_unicode_bidi_override`] and every
5295/// other UTF-8-aware predicate in this module) — the per-predicate
5296/// caller folds the `Some(c)` into its axis-specific reason wording
5297/// with the offending codepoint named verbatim as `U+XXXX`.
5298///
5299/// Lifted as a shared helper rather than inlined into each per-axis
5300/// predicate (the PRIME DIRECTIVE duplication-budget rule —
5301/// THEORY.md §I.3.5: "every recurring shape becomes a generator
5302/// before it becomes a pattern; every pattern becomes a library
5303/// before it becomes duplicated code. The duplication budget is
5304/// zero.") because two predicates ([`is_chart_description_shape`],
5305/// [`is_chart_maintainer_name_shape`]) carry the same UTF-8
5306/// free-form-prose accepted set and would otherwise inline the same
5307/// three-codepoint match arm verbatim — sibling lift to the
5308/// [`find_unicode_bidi_override`] helper one trajectory earlier on
5309/// the same two predicates. The third caller — every future
5310/// per-axis free-form-prose surface (a future Aplicacao-level
5311/// `:descricao` summary axis, a future per-`:contratos` edge
5312/// `:descricao` annotation, the future per-`:autores`-email-suffix
5313/// shape gate) — lands as a thin `if let Some(c) =
5314/// find_unicode_line_break(s) { … }` wrapper rather than re-inlining
5315/// the same codepoint match.
5316///
5317/// The arm is structurally distinct from the per-byte control-char
5318/// arm `[is_chart_description_shape]` already carries: the ASCII
5319/// line-break bytes `\n` (`0x0A`) and `\r` (`0x0D`) are caught at the
5320/// per-byte pass; the three non-ASCII line-break codepoints all
5321/// decode to multi-byte UTF-8 sequences (`C2 85` for U+0085, `E2 80
5322/// A8` for U+2028, `E2 80 A9` for U+2029) — every byte ≥ 0x80 per
5323/// UTF-8 grammar — that the per-byte non-ASCII pass deliberately
5324/// accepts (Unicode letters, em-dash, arrows are canonical
5325/// `:descricao` shapes). Only the typed codepoint scan catches them.
5326fn find_unicode_line_break(s: &str) -> Option<char> {
5327    s.chars()
5328        .find(|c| matches!(*c, '\u{0085}' | '\u{2028}' | '\u{2029}'))
5329}
5330
5331/// Scan `s` for any of the eight BMP Unicode invisible-format
5332/// codepoints — the Cf-category zero-width codepoints that have no
5333/// visible glyph in any conforming font yet ride verbatim through
5334/// string equality and parser lookup:
5335///
5336///   - U+00AD `SHY`    SOFT HYPHEN
5337///   - U+200B `ZWSP`   ZERO WIDTH SPACE
5338///   - U+2060 `WJ`     WORD JOINER
5339///   - U+2061 `FA`     FUNCTION APPLICATION
5340///   - U+2062 `IT`     INVISIBLE TIMES
5341///   - U+2063 `IS`     INVISIBLE SEPARATOR
5342///   - U+2064 `IP`     INVISIBLE PLUS
5343///   - U+FEFF `ZWNBSP` ZERO WIDTH NO-BREAK SPACE (BOM)
5344///
5345/// These codepoints break the THEORY.md §V.2 render-determinism
5346/// contract on a third axis from the visual-order class the sibling
5347/// [`find_unicode_bidi_override`] helper closes (the nine UAX #9
5348/// explicit-direction codepoints flip the rendered visual order) and
5349/// the single-line/multi-line class the sibling
5350/// [`find_unicode_line_break`] helper closes (the three UAX #14
5351/// non-ASCII line-break codepoints split a YAML 1.1 scalar): the
5352/// *invisible-identity* divergence. The author's editor view of
5353/// `caixa.lisp`, the chart-consumer's `helm list` / `helm search` /
5354/// Artifact Hub maintainer column, and every conformant terminal /
5355/// browser / editor agree on the visible glyph sequence (the
5356/// codepoint renders as nothing, so `"alice"` and
5357/// `"alice\u{200B}"` look identical end-to-end) — but the byte
5358/// sequence the YAML-plain-style-scalar carries verbatim differs
5359/// from the byte sequence the same author intends to read back, so
5360/// every byte-level grep / diff / equality comparison over the
5361/// rendered Chart.yaml disagrees with the visible-glyph match, the
5362/// Artifact Hub maintainer / description search index lookup misses
5363/// the authored identity entry because the byte sequence carries
5364/// invisible codepoints between letters, and a future per-author
5365/// CLA-signer lookup matches a visually-identical-but-byte-distinct
5366/// identity (the canonical "invisible-codepoint homograph" footgun).
5367/// The canonical authoring shapes that introduce these codepoints:
5368/// paste-from-Microsoft-Word (SHY auto-inserted at every hyphenation
5369/// candidate), paste-from-text-editor-saved-as-UTF-8-with-BOM (BOM
5370/// leading byte from Notepad / older VS Code defaults / Excel CSV
5371/// export), paste-from-typesetting-doc (ZWSP / WJ invisible word-
5372/// break hints from InDesign / LaTeX-rendered PDF copy-paste).
5373///
5374/// Returns the first offending codepoint in document order, or
5375/// `None` when `s` carries none of them. Iterates `chars()` once
5376/// (single UTF-8 decode pass, peer of [`find_unicode_bidi_override`]
5377/// and [`find_unicode_line_break`]) — the per-predicate caller folds
5378/// the `Some(c)` into its axis-specific reason wording with the
5379/// offending codepoint named verbatim as `U+XXXX`.
5380///
5381/// Excluded from the rejected set, on purpose:
5382///
5383///   - U+200C `ZWNJ` ZERO WIDTH NON-JOINER and U+200D `ZWJ` ZERO
5384///     WIDTH JOINER — both carry semantic compositional load in
5385///     Devanagari / Bengali / Persian script clusters (the
5386///     canonical "Persian name authoring" shape relies on ZWNJ to
5387///     break inappropriate ligatures) and in modern emoji ZWJ
5388///     sequences (👨‍💻 is `MAN` + U+200D `ZWJ` + `LAPTOP`); the
5389///     `:autores` / `:descricao` axes admit Unicode prose where
5390///     such sequences are the canonical authoring shape and a ban
5391///     would regress legitimate maintainer-name fixtures.
5392///   - U+200E `LRM` LEFT-TO-RIGHT MARK and U+200F `RLM`
5393///     RIGHT-TO-LEFT MARK — both are legitimate single-character
5394///     direction *hints* (not overrides) in mixed-script prose
5395///     (the canonical "Arabic name with embedded ASCII email"
5396///     shape relies on RLM to render the visual order reliably
5397///     across YAML / HTML consumers); the visible-order risk on
5398///     these axes is closed by the bidi-*override* helper (the 9
5399///     codepoints UAX #9 names as the Trojan Source vector), not
5400///     by the bidi-*marks*, so LRM/RLM remain accepted natively.
5401///   - Codepoints outside the BMP — Variation Selectors
5402///     Supplement (U+E0100..U+E01EF), Tag characters
5403///     (U+E0001..U+E007F) — sit outside the BMP and rarely
5404///     surface in realistic Helm chart metadata pasted from
5405///     editors; the BMP-restricted set captures the canonical
5406///     paste-from-Word / paste-from-BOM-editor / paste-from-
5407///     typesetting-doc / paste-from-math-formula class without
5408///     committing to a full Unicode `Default_Ignorable_Code_Point`
5409///     table.
5410///
5411/// Lifted as a shared helper rather than inlined into each per-axis
5412/// predicate (the PRIME DIRECTIVE duplication-budget rule —
5413/// THEORY.md §I.3.5: "every recurring shape becomes a generator
5414/// before it becomes a pattern; every pattern becomes a library
5415/// before it becomes duplicated code. The duplication budget is
5416/// zero.") because two predicates ([`is_chart_description_shape`],
5417/// [`is_chart_maintainer_name_shape`]) carry the same UTF-8
5418/// free-form-prose accepted set and would otherwise inline the same
5419/// eight-codepoint match arm verbatim — third lift in the UAX-driven
5420/// render-determinism trio (peer of [`find_unicode_bidi_override`]
5421/// on the visual-order axis and [`find_unicode_line_break`] on the
5422/// single-line/multi-line axis). The third caller — every future
5423/// per-axis free-form-prose surface (a future Aplicacao-level
5424/// `:descricao` summary axis, a future per-`:contratos` edge
5425/// `:descricao` annotation, the future per-`:autores`-email-suffix
5426/// shape gate) — lands as a thin `if let Some(c) =
5427/// find_unicode_invisible_format(s) { … }` wrapper rather than
5428/// re-inlining the same codepoint match.
5429///
5430/// The arm is structurally distinct from every prior arm on the
5431/// calling predicates: the per-byte control-char arm catches ASCII
5432/// `0x00..=0x1F` plus `0x7F` DEL; the per-byte non-ASCII pass
5433/// admits multi-byte UTF-8 sequences (Unicode letters, em-dash,
5434/// arrows are canonical shapes); the bidi-override helper catches
5435/// the 9 visual-order codepoints; the line-break helper catches
5436/// the 3 single-line-vs-multi-line codepoints. None overlap the
5437/// eight invisible-format codepoints here — each decodes to a
5438/// distinct multi-byte UTF-8 sequence (`C2 AD` for U+00AD,
5439/// `E2 80 8B` for U+200B, `E2 81 A0` for U+2060, `E2 81 A1` for
5440/// U+2061, `E2 81 A2` for U+2062, `E2 81 A3` for U+2063, `E2 81
5441/// A4` for U+2064, `EF BB BF` for U+FEFF) the per-byte non-ASCII
5442/// pass deliberately accepts; only the typed codepoint scan catches
5443/// them.
5444///
5445/// The four math-invisible operators U+2061..=U+2064 carry their
5446/// semantic load only inside mathematical typesetting (MathML
5447/// `<mo>` invisible operators, LaTeX `\,\,` thin-space-as-invisible-
5448/// times) — no realistic Helm chart `:descricao` or `:autores`
5449/// value is a math formula. The canonical authoring footgun is the
5450/// paste-from-MathJax-rendered-doc / paste-from-LaTeX-equation /
5451/// paste-from-InDesign-math-equation shape where MathJax /
5452/// LaTeX2RTF / InDesign export an invisible-operator codepoint
5453/// between adjacent symbols to preserve the semantic operator
5454/// reading for screen readers, and the codepoint silently rides
5455/// into the YAML scalar — same invisible-identity divergence class
5456/// the BMP four (SHY / ZWSP / WJ / BOM) close on the paste-from-
5457/// Word / paste-from-BOM-editor / paste-from-typesetting-doc class.
5458fn find_unicode_invisible_format(s: &str) -> Option<char> {
5459    s.chars().find(|c| {
5460        matches!(
5461            *c,
5462            '\u{00AD}'
5463                | '\u{200B}'
5464                | '\u{2060}'
5465                | '\u{2061}'
5466                | '\u{2062}'
5467                | '\u{2063}'
5468                | '\u{2064}'
5469                | '\u{FEFF}'
5470        )
5471    })
5472}
5473
5474/// Predicate: assert that `s` is a valid chart-description shape.
5475/// The `:descricao` axis is a free-form prose summary that lands in
5476/// the rendered `lareira-<nome>` Helm chart's `Chart.yaml`
5477/// `description:` field (a YAML scalar consumed by `helm list`,
5478/// `helm search`, Artifact Hub, and every chart-aware UI) and in
5479/// the chart's `README.md` header paragraph
5480/// (`caixa-helm/src/lib.rs:232`, `caixa-helm/src/lib.rs:333`).
5481/// The contract — modeled on the YAML 1.2 plain-style scalar
5482/// grammar and the Helm chart spec's expectation that
5483/// `description:` is a one-line summary:
5484///
5485///   - 1..=[`CHART_DESCRIPTION_MAX_LEN`] (512) bytes;
5486///   - no leading whitespace (paste-from-aligned-doc footgun —
5487///     YAML plain-style scalars round-trip trim-and-restore on
5488///     leading whitespace, so an authored `" foo"` lands as `"foo"`
5489///     in the rendered Chart.yaml and the round-trip back through
5490///     `caixa.lisp` silently drops the space);
5491///   - no trailing whitespace (paste-from-doc footgun — every YAML
5492///     dumper trims trailing whitespace from plain-style scalars,
5493///     so an authored `"foo "` round-trips inconsistently);
5494///   - no ASCII control characters anywhere (`0x00..=0x1F` plus
5495///     `0x7F` DEL) — tabs, newlines, carriage returns, and every
5496///     other control byte break the single-line YAML scalar shape
5497///     and the README header paragraph. The newline / CR arms are
5498///     the canonical paste-from-multiline-doc footgun; the tab arm
5499///     is the canonical paste-from-aligned-doc footgun; the
5500///     other-control-byte arm catches every more-exotic
5501///     paste-from-binary-blob shape (`0x00` NUL, `0x07` BEL,
5502///     `0x1B` ESC) that would silently land in the rendered
5503///     `Chart.yaml` as a YAML-illegal byte sequence and fail at
5504///     `helm lint` time far from the source caixa.lisp;
5505///   - non-ASCII bytes (UTF-8 continuation sequences) are
5506///     accepted — the canonical author shapes (`"Canonical
5507///     Rust→wasm32-wasip2 caixa Servico."`, `"FIXME — describe
5508///     this caixa"`) carry `→` (U+2192) and `—` (U+2014) and every
5509///     downstream consumer (YAML 1.2, Helm v3, every chart-aware
5510///     UI) round-trips Unicode losslessly;
5511///   - no Unicode bidirectional-override / isolate format
5512///     codepoints (U+202A `LRE`, U+202B `RLE`, U+202C `PDF`,
5513///     U+202D `LRO`, U+202E `RLO`, U+2066 `LRI`, U+2067 `RLI`,
5514///     U+2068 `FSI`, U+2069 `PDI`) — the nine codepoints UAX #9
5515///     names as the structural prerequisite of the "Trojan Source"
5516///     attack class (CVE-2021-42574 / Boucher & Anderson 2021)
5517///     that flip the rendered visual order of every following
5518///     character until a matching pop. Routed through the lifted
5519///     [`find_unicode_bidi_override`] helper so the same
5520///     nine-codepoint accepted set is shared with
5521///     [`is_chart_maintainer_name_shape`] on the sibling
5522///     YAML-plain-style-scalar surface, structurally consistent.
5523///     The non-ASCII byte arm above admits Unicode letters /
5524///     em-dash / arrows because YAML 1.2 + Helm v3 + every
5525///     chart-aware UI round-trip them losslessly; the bidi-override
5526///     codepoints break that round-trip discipline by class
5527///     (the byte sequence rides verbatim into the rendered
5528///     `Chart.yaml`'s `description:` value but renders differently
5529///     in `helm show chart` / Artifact Hub / `helm list` vs the
5530///     author's editor view of `caixa.lisp`), defeating the
5531///     THEORY.md §V.2 render-determinism contract every typed
5532///     slot carries on the same axis the per-byte CR/LF/control
5533///     arms above close for ASCII.
5534///   - no non-ASCII Unicode line-break codepoints (U+0085 `NEL`,
5535///     U+2028 `LS`, U+2029 `PS`) — the three codepoints UAX #14
5536///     (Unicode Line Breaking Algorithm) and the YAML 1.1 §4.1
5537///     b-char production both treat as line terminators outside
5538///     the ASCII `\n` / `\r` arms above. YAML 1.2 §5.4 retired
5539///     them per UTR #20, so YAML 1.2-strict parsers preserve them
5540///     verbatim while YAML 1.1 parsers (go-yaml v2 which Helm v3 /
5541///     kubectl link, `ruamel.yaml` in compat mode) split the
5542///     scalar on them — the same `:descricao` value parses as
5543///     single-line through one consumer and multi-line through
5544///     another, breaking cross-parser determinism on the same
5545///     axis the per-byte `\n` / `\r` arms close for ASCII.
5546///     Independently, every UAX #14 conformant text consumer
5547///     (editors, terminals, `helm list` / Artifact Hub web UIs)
5548///     breaks the visual line at these codepoints regardless of
5549///     YAML version, so the author's editor view of `caixa.lisp`
5550///     and the chart-consumer's rendered view diverge even when
5551///     both YAML parsers agree on the byte-level shape. Routed
5552///     through the lifted [`find_unicode_line_break`] helper so
5553///     the same three-codepoint accepted set is shared with
5554///     [`is_chart_maintainer_name_shape`], peer of the
5555///     [`find_unicode_bidi_override`] lift on the same two
5556///     predicates one trajectory earlier.
5557///   - no Unicode invisible-format codepoints (U+00AD `SHY`,
5558///     U+200B `ZWSP`, U+2060 `WJ`, U+2061 `FA` FUNCTION
5559///     APPLICATION, U+2062 `IT` INVISIBLE TIMES, U+2063 `IS`
5560///     INVISIBLE SEPARATOR, U+2064 `IP` INVISIBLE PLUS, U+FEFF
5561///     `ZWNBSP` / BOM) — the eight BMP Cf-category zero-width
5562///     codepoints with no visible glyph in any conforming font.
5563///     The author's editor view of `caixa.lisp` and the chart-
5564///     consumer's `helm list` / Artifact Hub description column
5565///     agree on the visible glyph sequence (`"Canonical Servico"`
5566///     and `"Canonical\u{200B}Servico"` render identically), but
5567///     the byte sequence the YAML-plain-style-scalar carries
5568///     verbatim differs — every byte-level grep / diff / equality
5569///     comparison and the Artifact Hub description-search index
5570///     lookup disagree silently with the visible-glyph match.
5571///     Closes the canonical paste-from-Microsoft-Word (SHY auto-
5572///     inserted at hyphenation candidates), paste-from-text-
5573///     editor-saved-as-UTF-8-with-BOM (leading BOM byte),
5574///     paste-from-typesetting-doc (ZWSP / WJ invisible word-break
5575///     hints), and paste-from-MathJax/LaTeX-rendered-formula
5576///     (FUNCTION APPLICATION / INVISIBLE TIMES / INVISIBLE
5577///     SEPARATOR / INVISIBLE PLUS — the four math-formula
5578///     invisible operators MathJax / LaTeX export between
5579///     adjacent symbols for screen-reader operator semantics)
5580///     footguns. Routed through the lifted
5581///     [`find_unicode_invisible_format`] helper so the same
5582///     eight-codepoint accepted set is shared with
5583///     [`is_chart_maintainer_name_shape`], third lift in the
5584///     UAX-driven render-determinism trio (peer of
5585///     [`find_unicode_bidi_override`] on the visual-order axis
5586///     and [`find_unicode_line_break`] on the single-line/multi-
5587///     line axis). The eight-codepoint set excludes U+200C
5588///     `ZWNJ` / U+200D `ZWJ` (legitimate compositional load in
5589///     Indic / Persian scripts and emoji ZWJ sequences) and
5590///     U+200E `LRM` / U+200F `RLM` (legitimate single-character
5591///     direction hints in mixed-script prose); the visible-order
5592///     risk on bidi overrides — not marks — is closed by the
5593///     prior helper.
5594///
5595/// The predicate is a *structural* floor — it enforces the
5596/// single-line printable-UTF-8 shape every realistic chart
5597/// description carries, not a per-byte alphabet check (which would
5598/// regress every non-ASCII canonical fixture). Same trajectory as
5599/// [`is_spdx_expression_shape`] (the ASCII-alphabet floor on the
5600/// `:licenca` axis) and [`is_git_repo_url`] (the URL-shape floor on
5601/// the `:repositorio` axis): the typed validator refuses the
5602/// downstream consumer's would-also-refuse shapes at the source
5603/// caixa.lisp boundary with the offending value named verbatim.
5604///
5605/// Returns the parser-shaped reason on rejection (without wrapping
5606/// in any error variant) so each per-axis caller —
5607/// [`crate::Caixa::validate_descricao`] for the universal
5608/// `:descricao` axis at validate time, every future per-description
5609/// axis (a future Aplicacao-level `:descricao` summary axis on
5610/// `mesh.pleme.io/v1alpha1/Caixa` CRs, a future Servico-level
5611/// per-`:contratos` edge `:descricao` annotation) — wraps the same
5612/// reason in its own typed `*Invalid { <axis>, reason }` variant.
5613/// The reason wording is axis-agnostic ("chart descriptions reject
5614/// leading whitespace") so every call site reading the same
5615/// diagnostic points at the same rule; drift between any two axes'
5616/// rule enforcement is a build error visible at this predicate, not
5617/// a per-renderer "this passed validate but `helm lint` rejected
5618/// the Chart.yaml `description:` value" surprise.
5619///
5620/// Empty input is rejected here (defensively) and at each call
5621/// site via the narrower [`crate::ManifestError::DescricaoEmpty`]
5622/// variant — the same empty-first cascade [`is_dns_1123_label`],
5623/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
5624/// [`is_nats_subject`], [`is_wasi_keyvalue_slot`],
5625/// [`is_git_ref_name`], [`is_git_oid`], [`is_git_repo_url`],
5626/// [`is_cargo_feature_name`], and [`is_spdx_expression_shape`] all
5627/// carry.
5628///
5629/// # Errors
5630///
5631/// Returns the parser-shaped reason naming the specific violation
5632/// (length / leading-whitespace / trailing-whitespace /
5633/// tab / newline / carriage-return / other-control-byte /
5634/// Unicode-bidi-override-codepoint / Unicode-line-break-codepoint),
5635/// without wrapping in any error variant — every caller maps the
5636/// same `String` into its own typed `*Invalid { <axis>, reason }`
5637/// enum variant.
5638pub fn is_chart_description_shape(s: &str) -> Result<(), String> {
5639    if s.is_empty() {
5640        return Err("must not be empty".to_string());
5641    }
5642    if s.len() > CHART_DESCRIPTION_MAX_LEN {
5643        return Err(format!(
5644            "exceeds chart description max length of {CHART_DESCRIPTION_MAX_LEN} bytes \
5645             (got {} bytes; realistic chart descriptions like `\"Canonical \
5646             Rust→wasm32-wasip2 caixa Servico.\"` rarely exceed ~64 bytes — this \
5647             length suggests a paste-from-doc multi-paragraph blob landed in the \
5648             `:descricao` slot)",
5649            s.len()
5650        ));
5651    }
5652    let bytes = s.as_bytes();
5653    if bytes[0] == b' ' {
5654        return Err(
5655            "must not start with whitespace (chart descriptions are single-line YAML \
5656             plain-style scalars; a leading space is the canonical \
5657             paste-from-aligned-doc footgun and round-trips inconsistently — every \
5658             YAML dumper trims leading whitespace from plain-style scalars, so the \
5659             authored space silently drops in the rendered Chart.yaml)"
5660                .to_string(),
5661        );
5662    }
5663    if *bytes.last().expect("non-empty checked above") == b' ' {
5664        return Err(
5665            "must not end with whitespace (chart descriptions don't terminate with \
5666             trailing whitespace; every YAML dumper trims trailing whitespace from \
5667             plain-style scalars, so the authored space round-trips inconsistently \
5668             back through `caixa.lisp`)"
5669                .to_string(),
5670        );
5671    }
5672    for &b in bytes {
5673        if b == b'\t' {
5674            return Err(
5675                "must not contain tab character (chart descriptions are single-line \
5676                 YAML plain-style scalars; tabs are the canonical \
5677                 paste-from-aligned-doc footgun and break the single-line scalar \
5678                 shape — every downstream YAML 1.2 parser is forbidden from \
5679                 emitting indentation tabs and tabs in plain-style scalars are \
5680                 implementation-defined)"
5681                    .to_string(),
5682            );
5683        }
5684        if b == b'\n' {
5685            return Err(
5686                "must not contain newline (chart descriptions are single-line YAML \
5687                 plain-style scalars; an embedded newline is the canonical \
5688                 paste-from-multiline-doc footgun and lands as a multi-line YAML \
5689                 block scalar in the rendered Chart.yaml — every chart-aware UI \
5690                 (`helm list`, `helm search`, Artifact Hub) renders the description \
5691                 in a single-line column, so the embedded newline is silently \
5692                 dropped at every downstream consumer)"
5693                    .to_string(),
5694            );
5695        }
5696        if b == b'\r' {
5697            return Err("must not contain carriage return (chart descriptions are \
5698                 single-line YAML plain-style scalars; a `\\r` byte is the canonical \
5699                 paste-from-Windows-CRLF-doc footgun and lands as a literal CR in \
5700                 the rendered Chart.yaml — every YAML 1.2 parser treats CR as a \
5701                 line terminator equivalent to LF, so the embedded CR is silently \
5702                 normalized to a newline at every downstream consumer)"
5703                .to_string());
5704        }
5705        if b < 0x20 || b == 0x7F {
5706            return Err(format!(
5707                "must not contain control character 0x{b:02x} (chart descriptions \
5708                 are printable UTF-8 single-line scalars; the control-byte arm \
5709                 catches paste-from-binary-blob footguns like `0x00` NUL, `0x07` \
5710                 BEL, `0x1b` ESC that would silently land in the rendered \
5711                 Chart.yaml as a YAML-illegal byte sequence and fail at `helm lint` \
5712                 time far from the source caixa.lisp)"
5713            ));
5714        }
5715    }
5716    if let Some(c) = find_unicode_bidi_override(s) {
5717        return Err(format!(
5718            "must not contain Unicode bidirectional-override codepoint U+{cp:04X} \
5719             (the nine codepoints UAX #9 names as the structural prerequisite of \
5720             the \"Trojan Source\" attack class — CVE-2021-42574 / Boucher & \
5721             Anderson 2021: U+202A `LRE`, U+202B `RLE`, U+202C `PDF`, U+202D `LRO`, \
5722             U+202E `RLO`, U+2066 `LRI`, U+2067 `RLI`, U+2068 `FSI`, U+2069 `PDI` \
5723             — flip the rendered visual order of every following character until a \
5724             matching pop, so a `:descricao` string visible to a human reading \
5725             `caixa.lisp` and the same string consumed by `helm show chart` / \
5726             `helm list` / Artifact Hub / every chart-aware UI disagree on the \
5727             order of the displayed content bytes. The byte sequence \
5728             ({utf8_seq}) rides verbatim into the rendered Chart.yaml's \
5729             `description:` value at the same axis the per-byte CR/LF/control \
5730             arms close for ASCII, but renders differently across consumers, \
5731             defeating the THEORY.md §V.2 render-determinism contract every typed \
5732             slot carries. The non-ASCII byte arm above admits Unicode letters / \
5733             em-dash / arrows because YAML 1.2 + Helm v3 round-trip them \
5734             losslessly; this codepoint breaks that round-trip discipline by \
5735             class. Drop the bidi-override codepoint; pure visual right-to-left \
5736             text (Hebrew, Arabic) is accepted natively without explicit \
5737             direction marks)",
5738            cp = c as u32,
5739            utf8_seq = c
5740                .encode_utf8(&mut [0u8; 4])
5741                .bytes()
5742                .map(|b| format!("0x{b:02X}"))
5743                .collect::<Vec<_>>()
5744                .join(" "),
5745        ));
5746    }
5747    if let Some(c) = find_unicode_line_break(s) {
5748        return Err(format!(
5749            "must not contain Unicode line-break codepoint U+{cp:04X} (the three \
5750             codepoints UAX #14 / YAML 1.1 §4.1 name as line terminators outside \
5751             the ASCII `\\n` / `\\r` arms above: U+0085 `NEL` NEXT LINE, U+2028 \
5752             `LS` LINE SEPARATOR, U+2029 `PS` PARAGRAPH SEPARATOR. YAML 1.2 §5.4 \
5753             retired them per UTR #20 so YAML 1.2-strict parsers preserve them \
5754             verbatim, but YAML 1.1 parsers (go-yaml v2 which Helm v3 / kubectl / \
5755             every Kubernetes client library transitively links, `ruamel.yaml` in \
5756             compat mode) still split scalars on them — the same `:descricao` \
5757             value parses as a single-line plain-style scalar through one \
5758             downstream consumer and a multi-line block scalar through another, \
5759             breaking cross-parser determinism on the same axis the per-byte \
5760             `\\n` / `\\r` arms close for ASCII. Independently, every UAX #14 \
5761             conformant text consumer (editors, terminals, `helm list` / \
5762             `helm search` / Artifact Hub web UIs) breaks the visual line at \
5763             these codepoints regardless of YAML version, so the author's editor \
5764             view of `caixa.lisp` and the chart-consumer's rendered view of the \
5765             `description:` field diverge even when both YAML parsers agree on \
5766             the byte-level shape, defeating the THEORY.md §V.2 render-\
5767             determinism contract every typed slot carries. The byte sequence \
5768             ({utf8_seq}) rides verbatim into the rendered Chart.yaml at the \
5769             same axis the per-byte `\\n` / `\\r` arms close for ASCII. Routed \
5770             through the shared [`find_unicode_line_break`] helper so the same \
5771             three-codepoint accepted set lives in exactly one place across the \
5772             [`is_chart_maintainer_name_shape`] sibling YAML-plain-style-scalar \
5773             surface, peer of the [`find_unicode_bidi_override`] lift on the \
5774             same two predicates one trajectory earlier. Drop the non-ASCII \
5775             line-break codepoint; split the value into separate logical lines \
5776             at the source if a multi-line summary is intended (the \
5777             `:descricao` axis is single-line by contract — the multi-paragraph \
5778             shape belongs in the chart `README.md` body, not the YAML \
5779             `description:` scalar))",
5780            cp = c as u32,
5781            utf8_seq = c
5782                .encode_utf8(&mut [0u8; 4])
5783                .bytes()
5784                .map(|b| format!("0x{b:02X}"))
5785                .collect::<Vec<_>>()
5786                .join(" "),
5787        ));
5788    }
5789    if let Some(c) = find_unicode_invisible_format(s) {
5790        return Err(format!(
5791            "must not contain Unicode invisible-format codepoint U+{cp:04X} (the \
5792             eight BMP Cf-category zero-width codepoints with no visible glyph in \
5793             any conforming font: U+00AD `SHY` SOFT HYPHEN, U+200B `ZWSP` ZERO \
5794             WIDTH SPACE, U+2060 `WJ` WORD JOINER, U+2061 `FA` FUNCTION \
5795             APPLICATION, U+2062 `IT` INVISIBLE TIMES, U+2063 `IS` INVISIBLE \
5796             SEPARATOR, U+2064 `IP` INVISIBLE PLUS, U+FEFF `ZWNBSP` ZERO WIDTH \
5797             NO-BREAK SPACE / BOM. The invisible-identity divergence: the \
5798             author's editor view of `caixa.lisp`, the chart-consumer's \
5799             `helm list` / `helm search` / Artifact Hub description column, \
5800             and every conformant terminal / browser / editor agree on the \
5801             visible glyph sequence (the codepoint renders as nothing, so \
5802             `\"Canonical Servico\"` and `\"Canonical\\u{{200B}}Servico\"` look \
5803             identical end-to-end), but the byte sequence the YAML-plain-style-\
5804             scalar carries verbatim differs — every byte-level grep / diff / \
5805             equality comparison over the rendered Chart.yaml `description:` \
5806             value disagrees with the visible-glyph match, and the Artifact Hub \
5807             description-search index lookup misses the authored entry because \
5808             the byte sequence carries an extra invisible codepoint between \
5809             letters. The canonical authoring shapes that silently introduce \
5810             these codepoints: paste-from-Microsoft-Word (SHY auto-inserted at \
5811             every hyphenation candidate), paste-from-text-editor-saved-as-UTF-8-\
5812             with-BOM (BOM leading byte from Notepad / older VS Code defaults), \
5813             paste-from-typesetting-doc (ZWSP / WJ invisible word-break hints \
5814             from InDesign / LaTeX-rendered PDF copy-paste), and paste-from-\
5815             MathJax/LaTeX-rendered-formula (FUNCTION APPLICATION / INVISIBLE \
5816             TIMES / INVISIBLE SEPARATOR / INVISIBLE PLUS — MathJax / LaTeX2RTF \
5817             / InDesign math-equation export emit one of these between adjacent \
5818             symbols to preserve operator semantics for screen readers, and the \
5819             codepoint silently rides into the YAML scalar with no visible \
5820             trace). The byte sequence ({utf8_seq}) rides verbatim into the \
5821             rendered Chart.yaml at the same axis the per-byte CR/LF/control \
5822             arms close for ASCII, but renders as nothing across consumers, \
5823             defeating the THEORY.md §V.2 render-determinism contract on a \
5824             third axis from the bidi-override (visual-order) and line-break \
5825             (single-line vs multi-line) classes the prior arms close. Routed \
5826             through the shared [`find_unicode_invisible_format`] helper so \
5827             the eight-codepoint accepted set lives in exactly one place \
5828             across the [`is_chart_maintainer_name_shape`] sibling \
5829             YAML-plain-style-scalar surface, third lift in the UAX-driven \
5830             render-determinism trio (peer of [`find_unicode_bidi_override`] \
5831             on the visual-order axis and [`find_unicode_line_break`] on the \
5832             single-line/multi-line axis). Drop the invisible codepoint; emoji \
5833             ZWJ sequences (U+200D for the 👨‍💻 family) and bidi direction-mark \
5834             codepoints (U+200E `LRM` / U+200F `RLM`) are accepted natively — \
5835             only the eight zero-semantic-content codepoints are rejected)",
5836            cp = c as u32,
5837            utf8_seq = c
5838                .encode_utf8(&mut [0u8; 4])
5839                .bytes()
5840                .map(|b| format!("0x{b:02X}"))
5841                .collect::<Vec<_>>()
5842                .join(" "),
5843        ));
5844    }
5845    Ok(())
5846}
5847
5848/// Maximum byte length of a chart-maintainer-name-shaped string. The
5849/// 128-byte cap is the axis-appropriate ceiling for the per-entry
5850/// identifier the `:autores` Vec axis carries: every realistic Helm
5851/// chart maintainer name in the wild (`"pleme-io"`, `"Pleme
5852/// Contributors"`, `"alice <alice@example.com>"`, `"François
5853/// Dupont"`) sits well under 64 bytes, and the 128-byte cap surfaces
5854/// the "paste-from-doc multi-paragraph blob landed in a single
5855/// `:autores` entry" footgun at validate time. Tighter than
5856/// [`CHART_DESCRIPTION_MAX_LEN`] (512) on the sibling free-form-prose
5857/// axis where multi-sentence summaries are the canonical shape;
5858/// peer with [`WIT_IDENT_MAX_LEN`] (128) on the sibling
5859/// short-identifier-class axis.
5860pub const CHART_MAINTAINER_NAME_MAX_LEN: usize = 128;
5861
5862/// Predicate: assert that `s` is a valid chart-maintainer-name shape.
5863/// The `:autores` axis is a per-entry maintainer identifier that lands
5864/// in the rendered `lareira-<nome>` Helm chart's `Chart.yaml`
5865/// `maintainers: [{name: …, email: null}]` array via
5866/// [`caixa-helm`]'s `build_chart_yaml` (`caixa-helm/src/lib.rs:251`);
5867/// each entry becomes the `name:` value of a single `Maintainer`
5868/// record (a YAML scalar consumed by `helm list`, `helm search`,
5869/// Artifact Hub's maintainer index, and every chart-aware UI). The
5870/// contract — modeled on the same YAML 1.2 plain-style scalar
5871/// grammar [`is_chart_description_shape`] enforces on the sibling
5872/// `:descricao` axis, with a tighter length cap for the per-entry
5873/// identifier class:
5874///
5875///   - 1..=[`CHART_MAINTAINER_NAME_MAX_LEN`] (128) bytes;
5876///   - no leading whitespace (paste-from-aligned-doc footgun —
5877///     YAML plain-style scalars round-trip trim-and-restore on
5878///     leading whitespace, so an authored `" pleme-io"` lands as
5879///     `"pleme-io"` in the rendered Chart.yaml and the round-trip
5880///     back through `caixa.lisp` silently drops the space);
5881///   - no trailing whitespace (paste-from-doc footgun — every YAML
5882///     dumper trims trailing whitespace from plain-style scalars,
5883///     so an authored `"pleme-io "` round-trips inconsistently);
5884///   - no ASCII control characters anywhere (`0x00..=0x1F` plus
5885///     `0x7F` DEL) — tabs, newlines, carriage returns, and every
5886///     other control byte break the single-line YAML scalar shape
5887///     and the `helm list` / `helm search` / Artifact Hub
5888///     maintainer-column rendering. The newline / CR arms are the
5889///     canonical paste-from-multiline-doc footgun (the author
5890///     pasted a multi-line block of author records into one
5891///     `:autores` entry instead of splitting them into one entry
5892///     per author); the tab arm is the canonical
5893///     paste-from-aligned-doc footgun; the other-control-byte
5894///     arm catches every more-exotic paste-from-binary-blob shape;
5895///   - non-ASCII bytes (UTF-8 continuation sequences) are accepted
5896///     — realistic maintainer names carry Unicode (`"François"`,
5897///     `"日本語"`, `"naïve"`) and every downstream consumer
5898///     (YAML 1.2, Helm v3, every chart-aware UI) round-trips
5899///     Unicode losslessly;
5900///   - no Unicode bidirectional-override / isolate format
5901///     codepoints (U+202A `LRE`, U+202B `RLE`, U+202C `PDF`,
5902///     U+202D `LRO`, U+202E `RLO`, U+2066 `LRI`, U+2067 `RLI`,
5903///     U+2068 `FSI`, U+2069 `PDI`) — the nine codepoints UAX #9
5904///     names as the structural prerequisite of the "Trojan Source"
5905///     attack class (CVE-2021-42574). A maintainer-name with an
5906///     embedded `RLO` flips the visual order of every trailing
5907///     byte, so an `:autores "alice\u{202E}example.com<bob@"` (the
5908///     paste-from-attacker-crafted-doc footgun) renders in
5909///     `helm list`'s maintainer column / Artifact Hub as
5910///     `alice<@bob>moc.elpmaxe` but rides verbatim into the
5911///     rendered Chart.yaml `maintainers:` array — same Trojan
5912///     Source class [`is_chart_description_shape`] closes on the
5913///     sibling `:descricao` axis. Routed through the same lifted
5914///     [`find_unicode_bidi_override`] helper so the nine-codepoint
5915///     accepted set is shared, structurally consistent.
5916///   - no non-ASCII Unicode line-break codepoints (U+0085 `NEL`,
5917///     U+2028 `LS`, U+2029 `PS`) — the three codepoints UAX #14
5918///     (Unicode Line Breaking Algorithm) and YAML 1.1 §4.1 b-char
5919///     production both treat as line terminators outside the
5920///     ASCII `\n` / `\r` arms above. YAML 1.2 §5.4 retired them
5921///     per UTR #20 so the cross-parser line-break disagreement
5922///     (go-yaml v2 / YAML 1.1 still splits; YAML 1.2-strict
5923///     parsers preserve) breaks the THEORY.md §V.2 render-
5924///     determinism contract on the same axis the per-byte `\n` /
5925///     `\r` arms close for ASCII. A maintainer-name with an
5926///     embedded U+2028 parses as one entry through a YAML 1.2
5927///     parser and as two `maintainers:` array entries through a
5928///     YAML 1.1 parser — same paste-from-multiline-doc class the
5929///     `\n` arm above closes, extended to the non-ASCII line-break
5930///     codepoints the per-byte non-ASCII pass deliberately
5931///     admits for Unicode letters. Routed through the same lifted
5932///     [`find_unicode_line_break`] helper so the three-codepoint
5933///     accepted set is shared with [`is_chart_description_shape`]
5934///     on the sibling YAML-plain-style-scalar surface,
5935///     structurally consistent.
5936///   - no Unicode invisible-format codepoints (U+00AD `SHY`,
5937///     U+200B `ZWSP`, U+2060 `WJ`, U+2061 `FA` FUNCTION
5938///     APPLICATION, U+2062 `IT` INVISIBLE TIMES, U+2063 `IS`
5939///     INVISIBLE SEPARATOR, U+2064 `IP` INVISIBLE PLUS, U+FEFF
5940///     `ZWNBSP` / BOM) — the eight BMP Cf-category zero-width
5941///     codepoints with no visible glyph. A maintainer-name with
5942///     an embedded U+200B (`"alice\u{200B}"`) renders identically
5943///     to `"alice"` in `helm list` / Artifact Hub's maintainer
5944///     column, yet the byte sequence is distinct — the Artifact
5945///     Hub maintainer-index lookup misses the authored `"alice"`
5946///     entry, and a future CLA-signer lookup matches a visually-
5947///     identical-but-byte-distinct identity (the canonical
5948///     invisible-codepoint homograph footgun on the maintainer-
5949///     identity axis). Closes the canonical paste-from-Microsoft-
5950///     Word (SHY), paste-from-text-editor-saved-as-UTF-8-with-BOM
5951///     (BOM), paste-from-typesetting-doc (ZWSP / WJ), and
5952///     paste-from-MathJax/LaTeX-rendered-formula (FUNCTION
5953///     APPLICATION / INVISIBLE TIMES / INVISIBLE SEPARATOR /
5954///     INVISIBLE PLUS — math-formula invisible operators
5955///     MathJax / LaTeX2RTF / InDesign emit between symbols for
5956///     screen-reader operator semantics) footguns. Routed through
5957///     the same lifted [`find_unicode_invisible_format`] helper
5958///     so the eight-codepoint accepted set is shared with
5959///     [`is_chart_description_shape`], third lift in the UAX-
5960///     driven render-determinism trio (peer of
5961///     [`find_unicode_bidi_override`] on the visual-order axis
5962///     and [`find_unicode_line_break`] on the single-line/multi-
5963///     line axis). The eight-codepoint set excludes U+200C
5964///     `ZWNJ` / U+200D `ZWJ` (emoji ZWJ sequences are canonical
5965///     for modern maintainer-display names) and U+200E `LRM` /
5966///     U+200F `RLM` (mixed-script direction hints are canonical
5967///     for "Arabic name with embedded ASCII email" shapes).
5968///
5969/// Same structural single-line printable-UTF-8 floor as
5970/// [`is_chart_description_shape`] — both `:descricao` and `:autores`
5971/// land as YAML plain-style scalars in the same `Chart.yaml` and
5972/// share every paste-from-doc footgun the YAML 1.2 grammar refuses
5973/// at parse time. The two predicates differ only on the byte
5974/// length cap: 512 bytes for `:descricao` (multi-sentence prose
5975/// shape) vs 128 bytes for `:autores` entries (short-identifier
5976/// shape). Returns the parser-shaped reason on rejection (without
5977/// wrapping in any error variant) so each per-axis caller —
5978/// [`crate::Caixa::validate_autores`] for the universal `:autores`
5979/// axis at validate time, every future per-maintainer-name axis (a
5980/// future caixa-registry maintainer-index entry, a future
5981/// chart-author CLA-signer lookup) — wraps the same reason in its
5982/// own typed `*Invalid { <axis>, reason }` variant.
5983///
5984/// Empty input is rejected here (defensively) and at each call
5985/// site via the narrower [`crate::ManifestError::AutorEmpty`]
5986/// variant — the same empty-first cascade [`is_dns_1123_label`],
5987/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
5988/// [`is_nats_subject`], [`is_wasi_keyvalue_slot`],
5989/// [`is_git_ref_name`], [`is_git_oid`], [`is_git_repo_url`],
5990/// [`is_cargo_feature_name`], [`is_spdx_expression_shape`], and
5991/// [`is_chart_description_shape`] all carry.
5992///
5993/// # Errors
5994///
5995/// Returns the parser-shaped reason naming the specific violation
5996/// (length / leading-whitespace / trailing-whitespace / tab /
5997/// newline / carriage-return / other-control-byte /
5998/// Unicode-bidi-override-codepoint), without wrapping in any error
5999/// variant — every caller maps the same `String` into its own typed
6000/// `*Invalid { <axis>, reason }` enum variant.
6001pub fn is_chart_maintainer_name_shape(s: &str) -> Result<(), String> {
6002    if s.is_empty() {
6003        return Err("must not be empty".to_string());
6004    }
6005    if s.len() > CHART_MAINTAINER_NAME_MAX_LEN {
6006        return Err(format!(
6007            "exceeds chart maintainer name max length of \
6008             {CHART_MAINTAINER_NAME_MAX_LEN} bytes (got {} bytes; realistic chart \
6009             maintainer names like `\"pleme-io\"`, `\"Pleme Contributors\"`, \
6010             `\"alice <alice@example.com>\"` rarely exceed ~64 bytes — this \
6011             length suggests a paste-from-doc multi-paragraph blob landed in a \
6012             single `:autores` entry instead of being split into one entry per \
6013             author)",
6014            s.len()
6015        ));
6016    }
6017    let bytes = s.as_bytes();
6018    if bytes[0] == b' ' {
6019        return Err(
6020            "must not start with whitespace (chart maintainer names are \
6021             single-line YAML plain-style scalars; a leading space is the \
6022             canonical paste-from-aligned-doc footgun and round-trips \
6023             inconsistently — every YAML dumper trims leading whitespace from \
6024             plain-style scalars, so the authored space silently drops in the \
6025             rendered Chart.yaml)"
6026                .to_string(),
6027        );
6028    }
6029    if *bytes.last().expect("non-empty checked above") == b' ' {
6030        return Err(
6031            "must not end with whitespace (chart maintainer names don't \
6032             terminate with trailing whitespace; every YAML dumper trims \
6033             trailing whitespace from plain-style scalars, so the authored \
6034             space round-trips inconsistently back through `caixa.lisp`)"
6035                .to_string(),
6036        );
6037    }
6038    for &b in bytes {
6039        if b == b'\t' {
6040            return Err(
6041                "must not contain tab character (chart maintainer names are \
6042                 single-line YAML plain-style scalars; tabs are the canonical \
6043                 paste-from-aligned-doc footgun and break the single-line \
6044                 scalar shape — every downstream YAML 1.2 parser is forbidden \
6045                 from emitting indentation tabs and tabs in plain-style scalars \
6046                 are implementation-defined)"
6047                    .to_string(),
6048            );
6049        }
6050        if b == b'\n' {
6051            return Err("must not contain newline (chart maintainer names are \
6052                 single-line YAML plain-style scalars; an embedded newline is \
6053                 the canonical paste-from-multiline-doc footgun — the author \
6054                 pasted a multi-line block of author records into one \
6055                 `:autores` entry instead of splitting them into one entry per \
6056                 author, and the result lands as a multi-line YAML block scalar \
6057                 in the rendered Chart.yaml `maintainers:` array)"
6058                .to_string());
6059        }
6060        if b == b'\r' {
6061            return Err("must not contain carriage return (chart maintainer \
6062                 names are single-line YAML plain-style scalars; a `\\r` byte \
6063                 is the canonical paste-from-Windows-CRLF-doc footgun and \
6064                 lands as a literal CR in the rendered Chart.yaml — every YAML \
6065                 1.2 parser treats CR as a line terminator equivalent to LF, \
6066                 so the embedded CR is silently normalized to a newline at \
6067                 every downstream consumer)"
6068                .to_string());
6069        }
6070        if b < 0x20 || b == 0x7F {
6071            return Err(format!(
6072                "must not contain control character 0x{b:02x} (chart \
6073                 maintainer names are printable UTF-8 single-line scalars; the \
6074                 control-byte arm catches paste-from-binary-blob footguns like \
6075                 `0x00` NUL, `0x07` BEL, `0x1b` ESC that would silently land \
6076                 in the rendered Chart.yaml as a YAML-illegal byte sequence \
6077                 and fail at `helm lint` time far from the source caixa.lisp)"
6078            ));
6079        }
6080    }
6081    if let Some(c) = find_unicode_bidi_override(s) {
6082        return Err(format!(
6083            "must not contain Unicode bidirectional-override codepoint U+{cp:04X} \
6084             (the nine codepoints UAX #9 names as the structural prerequisite of \
6085             the \"Trojan Source\" attack class — CVE-2021-42574 / Boucher & \
6086             Anderson 2021: U+202A `LRE`, U+202B `RLE`, U+202C `PDF`, U+202D `LRO`, \
6087             U+202E `RLO`, U+2066 `LRI`, U+2067 `RLI`, U+2068 `FSI`, U+2069 `PDI` \
6088             — flip the rendered visual order of every following character until a \
6089             matching pop, so an `:autores` entry visible to a human reading \
6090             `caixa.lisp` and the same entry consumed by `helm list` / Artifact \
6091             Hub's maintainer column disagree on the order of the displayed \
6092             content bytes. The byte sequence ({utf8_seq}) rides verbatim into \
6093             the rendered Chart.yaml `maintainers:` array at the same axis the \
6094             per-byte CR/LF/control arms close for ASCII, but renders \
6095             differently across consumers, defeating the THEORY.md §V.2 \
6096             render-determinism contract every typed slot carries. Routed through \
6097             the shared [`find_unicode_bidi_override`] helper so the same \
6098             nine-codepoint accepted set lives in exactly one place across the \
6099             [`is_chart_description_shape`] sibling YAML-plain-style-scalar \
6100             surface, structurally consistent. Drop the bidi-override codepoint; \
6101             pure visual right-to-left maintainer names (Hebrew, Arabic) are \
6102             accepted natively without explicit direction marks)",
6103            cp = c as u32,
6104            utf8_seq = c
6105                .encode_utf8(&mut [0u8; 4])
6106                .bytes()
6107                .map(|b| format!("0x{b:02X}"))
6108                .collect::<Vec<_>>()
6109                .join(" "),
6110        ));
6111    }
6112    if let Some(c) = find_unicode_line_break(s) {
6113        return Err(format!(
6114            "must not contain Unicode line-break codepoint U+{cp:04X} (the three \
6115             codepoints UAX #14 / YAML 1.1 §4.1 name as line terminators outside \
6116             the ASCII `\\n` / `\\r` arms above: U+0085 `NEL` NEXT LINE, U+2028 \
6117             `LS` LINE SEPARATOR, U+2029 `PS` PARAGRAPH SEPARATOR. YAML 1.2 §5.4 \
6118             retired them per UTR #20 so YAML 1.2-strict parsers preserve them \
6119             verbatim, but YAML 1.1 parsers (go-yaml v2 which Helm v3 / kubectl / \
6120             every Kubernetes client library transitively links, `ruamel.yaml` in \
6121             compat mode) still split scalars on them — an `:autores` entry with \
6122             an embedded U+2028 parses as one `maintainers:` array entry through \
6123             a YAML 1.2 parser and as two entries through a YAML 1.1 parser, \
6124             breaking cross-parser determinism on the same axis the per-byte \
6125             `\\n` / `\\r` arms close for ASCII. Independently, every UAX #14 \
6126             conformant text consumer (editors, terminals, `helm list` / \
6127             Artifact Hub's maintainer column) breaks the visual line at these \
6128             codepoints regardless of YAML version, so the author's editor view \
6129             of `caixa.lisp` and the chart-consumer's rendered view of the \
6130             `maintainers:` entry diverge even when both YAML parsers agree on \
6131             the byte-level shape, defeating the THEORY.md §V.2 render-\
6132             determinism contract every typed slot carries. The byte sequence \
6133             ({utf8_seq}) rides verbatim into the rendered Chart.yaml at the \
6134             same axis the per-byte `\\n` / `\\r` arms close for ASCII. Routed \
6135             through the shared [`find_unicode_line_break`] helper so the same \
6136             three-codepoint accepted set lives in exactly one place across the \
6137             [`is_chart_description_shape`] sibling YAML-plain-style-scalar \
6138             surface, peer of the [`find_unicode_bidi_override`] lift on the \
6139             same two predicates one trajectory earlier. Drop the non-ASCII \
6140             line-break codepoint; split the value into separate `:autores` \
6141             list entries at the source — the per-entry shape is single-line by \
6142             contract)",
6143            cp = c as u32,
6144            utf8_seq = c
6145                .encode_utf8(&mut [0u8; 4])
6146                .bytes()
6147                .map(|b| format!("0x{b:02X}"))
6148                .collect::<Vec<_>>()
6149                .join(" "),
6150        ));
6151    }
6152    if let Some(c) = find_unicode_invisible_format(s) {
6153        return Err(format!(
6154            "must not contain Unicode invisible-format codepoint U+{cp:04X} (the \
6155             eight BMP Cf-category zero-width codepoints with no visible glyph: \
6156             U+00AD `SHY` SOFT HYPHEN, U+200B `ZWSP` ZERO WIDTH SPACE, U+2060 \
6157             `WJ` WORD JOINER, U+2061 `FA` FUNCTION APPLICATION, U+2062 `IT` \
6158             INVISIBLE TIMES, U+2063 `IS` INVISIBLE SEPARATOR, U+2064 `IP` \
6159             INVISIBLE PLUS, U+FEFF `ZWNBSP` ZERO WIDTH NO-BREAK SPACE / BOM. \
6160             The maintainer-identity divergence: the author's editor view of \
6161             `caixa.lisp` and the `helm list` / Artifact Hub maintainer column \
6162             agree on the visible glyph sequence (`\"alice\"` and \
6163             `\"alice\\u{{200B}}\"` render identically as `alice`), but the byte \
6164             sequence the YAML-plain-style-scalar carries verbatim differs — \
6165             the Artifact Hub maintainer-index lookup misses the authored \
6166             `\"alice\"` entry because the byte sequence carries an extra \
6167             invisible codepoint, a future per-maintainer CLA-signer lookup \
6168             matches a visually-identical-but-byte-distinct identity (the \
6169             canonical invisible-codepoint homograph footgun), and every \
6170             byte-level diff / grep / equality comparison over the Chart.yaml \
6171             `maintainers:` array disagrees with the visible-glyph match. The \
6172             canonical authoring shapes that silently introduce these \
6173             codepoints: paste-from-Microsoft-Word (SHY auto-inserted at \
6174             every hyphenation candidate), paste-from-text-editor-saved-as-\
6175             UTF-8-with-BOM (BOM leading byte from Notepad / older VS Code \
6176             defaults / Excel CSV export), paste-from-typesetting-doc (ZWSP / \
6177             WJ invisible word-break hints from InDesign / LaTeX-rendered PDF \
6178             copy-paste), and paste-from-MathJax/LaTeX-rendered-formula \
6179             (FUNCTION APPLICATION / INVISIBLE TIMES / INVISIBLE SEPARATOR / \
6180             INVISIBLE PLUS — MathJax / LaTeX2RTF / InDesign math-equation \
6181             export emit one of these between adjacent symbols to preserve \
6182             operator semantics for screen readers, and the codepoint silently \
6183             rides into the YAML scalar with no visible trace). The byte \
6184             sequence ({utf8_seq}) rides verbatim into the rendered \
6185             Chart.yaml, but renders as nothing across consumers, defeating \
6186             the THEORY.md §V.2 render-determinism contract on a third axis \
6187             from the bidi-override (visual-order) and line-break (single-\
6188             line vs multi-line) classes the prior arms close. Routed through \
6189             the shared [`find_unicode_invisible_format`] helper so the \
6190             eight-codepoint accepted set is shared with \
6191             [`is_chart_description_shape`], third lift in the UAX-driven \
6192             render-determinism trio (peer of [`find_unicode_bidi_override`] \
6193             on the visual-order axis and [`find_unicode_line_break`] on the \
6194             single-line/multi-line axis). Drop the invisible codepoint; emoji \
6195             ZWJ sequences (U+200D for the 👨‍💻 family) and bidi direction-mark \
6196             codepoints (U+200E `LRM` / U+200F `RLM`) are accepted natively \
6197             for mixed-script maintainer names — only the eight zero-semantic-\
6198             content codepoints are rejected)",
6199            cp = c as u32,
6200            utf8_seq = c
6201                .encode_utf8(&mut [0u8; 4])
6202                .bytes()
6203                .map(|b| format!("0x{b:02X}"))
6204                .collect::<Vec<_>>()
6205                .join(" "),
6206        ));
6207    }
6208    Ok(())
6209}
6210
6211/// Maximum byte length of a chart-keyword-shaped string. The 20-byte
6212/// cap matches Cargo's `[package] keywords` rule
6213/// (<https://doc.rust-lang.org/cargo/reference/manifest.html#the-keywords-field>:
6214/// "Each keyword should be ASCII text, start with a letter, and only
6215/// contain letters, numbers, _ or -. Keywords are case-insensitive and
6216/// limited to a maximum length of 20 characters.") — the same parser
6217/// crates.io routes its `keywords:` array entries through at publish
6218/// time. Tighter than every peer length cap on the typed Caixa surface
6219/// ([`CHART_MAINTAINER_NAME_MAX_LEN`] 128 on the sibling chart-metadata
6220/// `Vec<String>` axis, [`CARGO_FEATURE_NAME_MAX_LEN`] 64 on the sibling
6221/// `:caracteristicas` per-entry axis, [`CHART_DESCRIPTION_MAX_LEN`] 512
6222/// on the free-form-prose axis); the search-tag class is the tightest
6223/// short-identifier shape on the typed surface — every realistic
6224/// `:etiquetas` entry in the wild (`"iac"`, `"aws"`, `"pangea"`,
6225/// `"hello-world"`, `"tatara-lisp"`, `"caixa-servico"`,
6226/// `"infrastructure"`, `"pangea-native"`) sits well under 20 bytes,
6227/// and the 20-byte cap surfaces the "paste-from-doc multi-tag blob
6228/// landed in a single `:etiquetas` entry" footgun (`"web-service web
6229/// app"`, `"mesh,http,grpc"`) at validate time.
6230pub const CHART_KEYWORD_MAX_LEN: usize = 20;
6231
6232/// Predicate: assert that `s` is a valid chart-keyword shape. The
6233/// `:etiquetas` axis is a per-entry registry-search-tag identifier
6234/// that lands in the rendered `lareira-<nome>` Helm chart's
6235/// `Chart.yaml` `keywords:` array via [`caixa-helm`]'s
6236/// `build_chart_yaml` (folded through a [`std::collections::BTreeSet`]
6237/// alongside the four substrate-fixed tags `lareira` / `wasm` /
6238/// `tatara-lisp` / `caixa-servico`) and indexes the chart through
6239/// Artifact Hub's keyword-search axis + the future caixa-registry's
6240/// keyword index. The contract — modeled on Cargo's crates.io
6241/// `[package] keywords` grammar (the parser the crates.io publish API
6242/// routes every `keywords:` entry through at publish time), narrowed
6243/// to the strict ASCII subset every realistic search tag uses:
6244///
6245///   - 1..=[`CHART_KEYWORD_MAX_LEN`] (20) bytes;
6246///   - first byte: ASCII letter (`A-Z` or `a-z`). Leading digit, `-`,
6247///     `_`, whitespace, control, and non-ASCII are each surfaced with
6248///     a self-locating reason naming the canonical authoring footgun
6249///     (paste-from-numbered-list `"1foo"`, kebab-leak `"-foo"`,
6250///     snake-leak `"_foo"`, paste-from-aligned-doc whitespace,
6251///     paste-from-Unicode-doc non-ASCII);
6252///   - remaining bytes: ASCII alphanumeric, `_`, or `-` (Cargo's
6253///     crates.io-accepted continuation set; tighter than
6254///     [`is_cargo_feature_name`]'s `_`/`-`/`+`/`.` continuation set —
6255///     `+` and `.` are not part of the keyword grammar). Whitespace,
6256///     `,` / `/` / `;` / `.` list-separator confusions, control bytes,
6257///     and non-ASCII bytes are each surfaced with a self-locating
6258///     reason naming the canonical authoring footgun (multi-tag blob
6259///     in one entry, CSV-list-belongs-to-list-grammar miscomprehension,
6260///     CR/LF paste-from-doc, NFC/NFD normalization drift).
6261///
6262/// Returns the parser-shaped reason on rejection (without wrapping in
6263/// any error variant) so each per-axis caller —
6264/// [`crate::Caixa::validate_etiquetas`] for the universal `:etiquetas`
6265/// axis at validate time, every future per-keyword axis (a future
6266/// caixa-registry keyword-index lookup, a future Artifact Hub-keyword
6267/// scraper validator, a future per-Aplicacao aggregated keyword set)
6268/// — wraps the same reason in its own typed `*Invalid { <axis>, reason }`
6269/// variant.
6270///
6271/// Empty input is rejected here (defensively) and at each call site
6272/// via the narrower [`crate::ManifestError::EtiquetaEmpty`] variant —
6273/// the same empty-first cascade [`is_dns_1123_label`],
6274/// [`is_gateway_api_http_path`], [`is_wit_world_ref`],
6275/// [`is_nats_subject`], [`is_wasi_keyvalue_slot`], [`is_git_ref_name`],
6276/// [`is_git_oid`], [`is_git_repo_url`], [`is_cargo_feature_name`],
6277/// [`is_spdx_expression_shape`], [`is_chart_description_shape`], and
6278/// [`is_chart_maintainer_name_shape`] all carry at their call sites.
6279///
6280/// # Errors
6281///
6282/// Returns the parser-shaped reason naming the specific violation
6283/// (length / first-byte-class / continuation-byte-class / whitespace /
6284/// control-char / non-ASCII / `,`-list-separator-confusion /
6285/// `/`-path-separator-confusion / `;`-list-separator-confusion /
6286/// `.`-namespace-confusion), without wrapping in any error variant —
6287/// every caller maps the same `String` into its own typed
6288/// `*Invalid { <axis>, reason }` enum variant.
6289pub fn is_chart_keyword_shape(s: &str) -> Result<(), String> {
6290    if s.is_empty() {
6291        return Err("must not be empty".to_string());
6292    }
6293    if s.len() > CHART_KEYWORD_MAX_LEN {
6294        return Err(format!(
6295            "exceeds chart keyword max length of {CHART_KEYWORD_MAX_LEN} bytes (got \
6296             {} bytes; legitimate `:etiquetas` search tags rarely exceed ~12 bytes — \
6297             this length suggests a paste-from-doc multi-tag blob landed in a single \
6298             `:etiquetas` entry instead of being split into one entry per tag, e.g. \
6299             `(\"mesh\" \"http\" \"grpc\")` not `(\"mesh-http-grpc-rpc-wasm\")`. \
6300             Cargo's crates.io publish API enforces the same 20-byte cap on its \
6301             `keywords:` array at publish time)",
6302            s.len()
6303        ));
6304    }
6305    let bytes = s.as_bytes();
6306    let first = bytes[0];
6307    if !first.is_ascii_alphabetic() {
6308        let msg = if first == b' ' || first == b'\t' {
6309            "must not start with whitespace (chart keywords are single-token \
6310             search-tag identifiers; the leading-whitespace arm is the canonical \
6311             paste-from-aligned-doc footgun and round-trips inconsistently — every \
6312             YAML 1.2 dumper trims leading whitespace from plain-style scalars, so \
6313             the authored space silently drops in the rendered Chart.yaml \
6314             `keywords:` array)"
6315                .to_string()
6316        } else if first == b'-' {
6317            "must not start with `-` (Cargo's crates.io keyword grammar rejects a \
6318             leading hyphen — `-` is a legitimate continuation character between \
6319             alphanumeric segments but the canonical CLI-argument-injection / \
6320             kebab-leak footgun at the start; drop the leading `-`, e.g. \
6321             `\"tatara-lisp\"` not `\"-tatara-lisp\"`)"
6322                .to_string()
6323        } else if first == b'_' {
6324            "must not start with `_` (Cargo's crates.io keyword grammar requires the \
6325             first character be an ASCII letter — `_` is a legitimate continuation \
6326             character between alphanumeric segments but the canonical \
6327             snake-leak / hidden-identifier footgun at the start; drop the leading \
6328             `_`, e.g. `\"caixa-servico\"` not `\"_caixa_servico\"`)"
6329                .to_string()
6330        } else if first.is_ascii_digit() {
6331            format!(
6332                "must not start with digit {ch:?} (Cargo's crates.io keyword grammar \
6333                 requires the first character be an ASCII letter — a digit at the \
6334                 start is the canonical paste-from-numbered-list footgun, e.g. the \
6335                 author copied `1. mesh` from a numbered doc and the `1` leaked \
6336                 into the tag; drop the leading digit, e.g. `\"v2\"` not `\"2v\"`)",
6337                ch = first as char
6338            )
6339        } else if first < 0x20 || first == 0x7F {
6340            format!(
6341                "must not start with control character 0x{first:02x} (Cargo's \
6342                 crates.io keyword grammar rejects ASCII control characters; the \
6343                 CR/LF arm is the canonical paste-from-multiline-doc footgun)"
6344            )
6345        } else if first >= 0x80 {
6346            format!(
6347                "must not start with non-ASCII byte 0x{first:02x} (Cargo's \
6348                 crates.io keyword grammar is strict ASCII; the non-ASCII arm \
6349                 catches the canonical paste-from-Unicode-doc footgun — every \
6350                 legitimate search tag is a kebab-case ASCII identifier like \
6351                 `\"mesh\"`, `\"wasm\"`, `\"tatara-lisp\"`. Raw non-ASCII silently \
6352                 round-trips inconsistently across NFC/NFD normalization on APFS / \
6353                 case-folding filesystems and breaks the Artifact Hub keyword \
6354                 search index lookup)"
6355            )
6356        } else {
6357            format!(
6358                "must start with an ASCII letter, got {ch:?} (Cargo's crates.io \
6359                 keyword grammar rejects every non-letter first character — the \
6360                 canonical search tags are kebab-case ASCII identifiers starting \
6361                 with a letter, like `\"mesh\"`, `\"wasm\"`, `\"hello-world\"`)",
6362                ch = first as char
6363            )
6364        };
6365        return Err(msg);
6366    }
6367    for &b in &bytes[1..] {
6368        let valid = b.is_ascii_alphanumeric() || b == b'_' || b == b'-';
6369        if !valid {
6370            let msg = if b == b' ' || b == b'\t' {
6371                format!(
6372                    "must not contain whitespace character {ch:?} (Cargo's \
6373                     crates.io keyword grammar rejects whitespace; search tags are \
6374                     single-token identifiers — use `-` or `_` to separate \
6375                     kebab-case / snake-case segments instead, or split into \
6376                     separate `:etiquetas` entries: `(\"web\" \"service\")` not \
6377                     `(\"web service\")`)",
6378                    ch = b as char
6379                )
6380            } else if b == b',' {
6381                "must not contain `,` (the comma separator belongs to the \
6382                 `:etiquetas` list grammar between entries, not to the keyword \
6383                 grammar within an entry — split the value into separate list \
6384                 entries: `(\"mesh\" \"http\" \"grpc\")` not `(\"mesh,http,grpc\")`. \
6385                 The author confused the CSV-style list-separator convention with \
6386                 the list grammar)"
6387                    .to_string()
6388            } else if b == b'/' {
6389                "must not contain `/` (Cargo's crates.io keyword grammar rejects \
6390                 path-style separators within a tag; the segment separator within \
6391                 a search tag is `-` or `_`, and multi-segment paths belong as \
6392                 separate `:etiquetas` entries: `(\"caixa\" \"servico\")` not \
6393                 `(\"caixa/servico\")`)"
6394                    .to_string()
6395            } else if b == b';' {
6396                "must not contain `;` (the semicolon separator is not part of the \
6397                 `:etiquetas` list grammar — split the value into separate list \
6398                 entries: `(\"mesh\" \"http\")` not `(\"mesh;http\")`. The author \
6399                 confused another lisp-list-style separator with the list \
6400                 grammar)"
6401                    .to_string()
6402            } else if b == b'.' {
6403                "must not contain `.` (Cargo's crates.io keyword grammar excludes \
6404                 `.` from the continuation set — the canonical \
6405                 namespace-confusion / version-suffix footgun, e.g. `\"http.1\"` \
6406                 / `\"v1.0\"`; use `-` instead, e.g. `\"http-1\"` / `\"v1-0\"`)"
6407                    .to_string()
6408            } else if b == b'\n' {
6409                "must not contain newline (chart keywords are single-line \
6410                 single-token identifiers; an embedded newline is the canonical \
6411                 paste-from-multiline-doc footgun — the author pasted a multi-tag \
6412                 block into one `:etiquetas` entry instead of splitting into one \
6413                 entry per tag)"
6414                    .to_string()
6415            } else if b == b'\r' {
6416                "must not contain carriage return (chart keywords are single-line \
6417                 single-token identifiers; a `\\r` byte is the canonical \
6418                 paste-from-Windows-CRLF-doc footgun and lands as a literal CR in \
6419                 the rendered Chart.yaml `keywords:` array)"
6420                    .to_string()
6421            } else if b < 0x20 || b == 0x7F {
6422                format!(
6423                    "must not contain control character 0x{b:02x} (Cargo's \
6424                     crates.io keyword grammar rejects ASCII control characters; \
6425                     the control-byte arm catches paste-from-binary-blob footguns \
6426                     like `0x00` NUL, `0x07` BEL, `0x1b` ESC, `0x7f` DEL that \
6427                     would silently land in the rendered Chart.yaml \
6428                     `keywords:` array as a YAML-illegal byte sequence)"
6429                )
6430            } else if b >= 0x80 {
6431                format!(
6432                    "must not contain non-ASCII byte 0x{b:02x} (Cargo's crates.io \
6433                     keyword grammar is strict ASCII; the non-ASCII arm catches \
6434                     the canonical paste-from-Unicode-doc footgun — raw non-ASCII \
6435                     silently round-trips inconsistently across NFC/NFD \
6436                     normalization on APFS / case-folding filesystems and breaks \
6437                     the Artifact Hub keyword search index lookup)"
6438                )
6439            } else {
6440                format!(
6441                    "contains invalid character {ch:?} (Cargo's crates.io keyword \
6442                     grammar allows only `[A-Za-z0-9_-]` after the first \
6443                     character)",
6444                    ch = b as char
6445                )
6446            };
6447            return Err(msg);
6448        }
6449    }
6450    Ok(())
6451}
6452
6453/// Tagged reason a caixa-author-supplied path can fail the
6454/// sandboxed-relative shape gate every callback / script path must
6455/// pass for the layout checker's `root.join(p)` to stay inside the
6456/// caixa root.
6457///
6458/// Returned by [`is_sandboxed_relative_path`] so each per-axis caller
6459/// — [`crate::BehaviorSpec::validate`] on `:behavior :on-*` paths
6460/// (b0c8389), [`crate::UpgradeInstruction::validate`]'s `StateChange`
6461/// arm on `:upgrade-from :state-change :script` (26da2c7), every
6462/// future axis admitting a user-supplied path — match-and-wraps the
6463/// tag into its own typed `*Invalid { slot, path }` enum variant so
6464/// the diagnostic still names *which slot* carried the malformed
6465/// value. The tag is axis-agnostic; the wrapping per-axis variant
6466/// carries the slot identity.
6467///
6468/// Sibling discriminator-style of the per-arm reason substrings every
6469/// value-shape predicate already exposes (`is_dns_1123_label`,
6470/// `is_gateway_api_http_path`, …) — but typed rather than string-
6471/// shaped, because the per-axis variants for path violations were
6472/// already split three ways (`EmptyPath` / `AbsolutePath` /
6473/// `ParentEscape` in `BehaviorError`; `EmptyScript` / `AbsoluteScript`
6474/// / `ParentEscapeScript` in `UpgradeError`), so collapsing them to a
6475/// single `*PathInvalid { reason }` variant would *regress* the
6476/// diagnostic shape rather than preserve it.
6477#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6478pub enum PathShapeViolation {
6479    /// The path string is empty — `PathBuf::new()` or the
6480    /// canonical "I declared the slot but left the value blank"
6481    /// authoring footgun. `root.join(PathBuf::new())` resolves to
6482    /// `root` itself, silently pointing the runtime's `LisleLoader`
6483    /// at the project root rather than a file.
6484    Empty,
6485    /// The path is absolute — `Path::join` *replaces* the base
6486    /// with an absolute right-hand side, so `root.join("/etc/passwd")`
6487    /// resolves to `"/etc/passwd"` and escapes the project sandbox
6488    /// entirely. The Lunatic-style sandbox discipline
6489    /// ([`theory/INSPIRATIONS.md` §III.1][i31]) requires every
6490    /// author-supplied path to live under the caixa root.
6491    ///
6492    /// [i31]: https://github.com/pleme-io/theory/blob/main/INSPIRATIONS.md
6493    Absolute,
6494    /// The path contains a [`Component::ParentDir`] component anywhere
6495    /// — `root.join("../sibling/x")` traverses above the caixa root,
6496    /// the same sandbox-escape vector via parent-directory traversal.
6497    /// Caught regardless of where the `..` component sits (leading,
6498    /// mid-path, trailing) so a future relaxation that only checks
6499    /// one position surfaces at this one predicate.
6500    ParentEscape,
6501}
6502
6503/// Predicate: assert that `path` is a *sandboxed-relative* path —
6504/// the shape every caixa-author-supplied callback / script path must
6505/// take so the layout checker's `root.join(p)` resolves inside the
6506/// caixa root sandbox. The contract:
6507///
6508///   - non-empty (`PathBuf::new()` → `Empty`);
6509///   - relative (absolute paths replace the base under
6510///     [`Path::join`] semantics → `Absolute`);
6511///   - no [`Component::ParentDir`] components anywhere (traversal
6512///     above the caixa root → `ParentEscape`).
6513///
6514/// Returns [`PathShapeViolation`] tagging the specific failure;
6515/// each per-axis caller match-and-wraps the variant in its own
6516/// typed `*Invalid { slot, path }` enum variant so the diagnostic
6517/// still names *which slot* carried the malformed value. The
6518/// arm-ordering is the same `Empty → Absolute → ParentEscape`
6519/// every prior inlined copy followed (b0c8389 [`crate::BehaviorSpec`],
6520/// 26da2c7 [`crate::UpgradeInstruction::StateChange`]), so any
6521/// caller migrating to the lifted predicate preserves its existing
6522/// per-slot diagnostic precedence by construction.
6523///
6524/// Lifted from `caixa-core::behavior` and `caixa-core::upgrade`
6525/// where the same three-step gate was inlined verbatim across two
6526/// call sites — the PRIME DIRECTIVE duplication-budget rule
6527/// (THEORY.md §I.3.5: "every recurring shape becomes a generator
6528/// before it becomes a pattern; every pattern becomes a library
6529/// before it becomes duplicated code. The duplication budget is
6530/// zero.") promotes the gate to a typed substrate-side predicate
6531/// on the same trajectory the M2-overlay and label-selector helpers
6532/// (9e3a057, 9d09cfb, 9dbeafd, 31455a7, 07a4544, 8b4db42) already
6533/// follow. The third caller — the future M3/M4 axis admitting a
6534/// user-supplied path (the future `:entrada :tls-cert` /
6535/// `:entrada :tls-key` PEM-file axes, the future
6536/// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-path
6537/// validator, the future per-Servico pre-warm script axis) — lands
6538/// as a thin five-line wrapper rather than re-inlining the same
6539/// three checks.
6540///
6541/// Pairs with the per-axis empty / absolute / parent-escape variants
6542/// on [`crate::BehaviorError`] and [`crate::UpgradeError`] — those
6543/// remain the typed surface authors see; this predicate is the
6544/// single-source-of-truth gate the caixa-build pipeline consults to
6545/// produce them.
6546///
6547/// # Errors
6548///
6549/// Returns the [`PathShapeViolation`] tag identifying the specific
6550/// violation ([`PathShapeViolation::Empty`] / [`PathShapeViolation::Absolute`]
6551/// / [`PathShapeViolation::ParentEscape`]) so each per-axis caller
6552/// match-and-wraps it into its own typed `*Path` / `*Script` enum
6553/// variant (preserving the per-slot diagnostic granularity the inline
6554/// pre-lift gates already produced).
6555pub fn is_sandboxed_relative_path(path: &Path) -> Result<(), PathShapeViolation> {
6556    if path.as_os_str().is_empty() {
6557        return Err(PathShapeViolation::Empty);
6558    }
6559    if path.is_absolute() {
6560        return Err(PathShapeViolation::Absolute);
6561    }
6562    if path.components().any(|c| matches!(c, Component::ParentDir)) {
6563        return Err(PathShapeViolation::ParentEscape);
6564    }
6565    Ok(())
6566}
6567
6568/// The canonical tatara-lisp source-file extension every M2 typed
6569/// path-slot the M2.5 wasm-engine instantiator reads through
6570/// `tatara_lisp::read` at instance-start time must terminate in.
6571///
6572/// Strict lowercase: the byte-size / duration codecs and every other
6573/// shape-gate predicate in this module are case-sensitive on unit /
6574/// scheme / label boundaries, so a strict `lisp` shape matches the
6575/// downstream accepted set without case-folding drift (an uppercase
6576/// `.LISP` / `.Lisp` shape that a case-insensitive volume's existence
6577/// check would match the on-disk file would still mismatch the
6578/// canonical form the codec emits, breaking the THEORY.md §V.2.7
6579/// render-determinism contract every typed slot carries).
6580pub const LISP_SOURCE_EXTENSION: &str = "lisp";
6581
6582/// Predicate: assert that `path` terminates in the canonical
6583/// [`LISP_SOURCE_EXTENSION`] (lowercase `.lisp`) — the file-type
6584/// shape every M2 typed path-slot the wasm-engine instantiator reads
6585/// as tatara-lisp source must take. The contract:
6586///
6587///   - the path has an extension component (no-extension paths like
6588///     `"lib/init"` or `"a"` fail);
6589///   - the extension's UTF-8 string form is exactly `"lisp"` —
6590///     lowercase, no trailing residue, no double-extension shadow
6591///     like `".lisp.bak"`.
6592///
6593/// Returns `true` on accept, `false` on reject. Each per-axis caller
6594/// — [`crate::BehaviorSpec::validate`] on `:behavior :on-*` paths
6595/// (c97815a), [`crate::UpgradeInstruction::StateChange::validate`]
6596/// on `:upgrade-from :state-change :script` (this commit), every
6597/// future axis admitting a tatara-lisp source path — wraps the
6598/// boolean into its own typed `*NonLispExtension { slot, path }` /
6599/// `*NonLispExtensionScript { script }` enum variant so the
6600/// diagnostic still names *which slot* carried the non-`.lisp`
6601/// value. The predicate is axis-agnostic; the wrapping per-axis
6602/// variant carries the slot identity.
6603///
6604/// Lifted from `caixa-core::behavior` where the same single-line
6605/// gate (`path.extension().and_then(|ext| ext.to_str()) ==
6606/// Some("lisp")`) was inlined verbatim across the first call site
6607/// (`BehaviorSpec::validate_callback_path`) — the PRIME DIRECTIVE
6608/// duplication-budget rule (THEORY.md §I.3.5: "every recurring shape
6609/// becomes a generator before it becomes a pattern; every pattern
6610/// becomes a library before it becomes duplicated code. The
6611/// duplication budget is zero.") promotes the gate to a typed
6612/// substrate-side predicate on the same trajectory the path-shape
6613/// gate [`is_sandboxed_relative_path`] already follows (lifted from
6614/// the same two call sites once the second consumer appeared). The
6615/// third caller — the future `:bibliotecas` per-entry tatara-lisp
6616/// source-file axis (the `feira build` loop reads each through the
6617/// same `tatara_lisp::read` reader at parse time), the future `:exe`
6618/// `:kind Binario` entry-point axis (the nix-built binary's entry
6619/// point loads as Lisp source), the future M2.5 wasm-engine
6620/// pre-warm hook axis — lands as a thin two-line wrapper rather
6621/// than re-inlining the same extension check.
6622///
6623/// Pairs with the per-axis `*NonLispExtension` / `*NonLispExtensionScript`
6624/// variants on [`crate::BehaviorError`] and [`crate::UpgradeError`]
6625/// — those remain the typed surface authors see; this predicate is
6626/// the single-source-of-truth gate the caixa-build pipeline consults
6627/// to produce them.
6628#[must_use]
6629pub fn is_lisp_extension(path: &Path) -> bool {
6630    path.extension().and_then(|ext| ext.to_str()) == Some(LISP_SOURCE_EXTENSION)
6631}
6632
6633/// The canonical compound suffix every `:servicos` entry — the
6634/// ComputeUnit-CR axis the M2 typed-substrate caixa-helm /
6635/// caixa-flux renderers consume via `serde_yaml::from_str` — must
6636/// terminate in. Two-segment shape (`.computeunit.yaml`) rather than
6637/// a single `.yaml` extension: the `.computeunit` segment routes
6638/// authoring-time to the typed `ComputeUnit` CR shape the
6639/// `pleme-computeunit` library chart resolves, distinguishing the
6640/// slot's accepted set from the open `.yaml` universe (Helm
6641/// `values.yaml`, FluxCD `Kustomization.yaml`, the generic K8s
6642/// manifest YAML every operator emits) — same axis-discipline the
6643/// peer [`LISP_SOURCE_EXTENSION`] sibling carries on the tatara-lisp-
6644/// source axis but with a compound suffix because
6645/// [`Path::extension`] only returns the post-last-`.` segment
6646/// (`"yaml"` for `foo.computeunit.yaml`), so the predicate routes
6647/// through [`Path::file_name`] and a string `ends_with` check on the
6648/// full suffix instead.
6649///
6650/// Strict lowercase: every other shape-gate predicate in this module
6651/// is case-sensitive on unit / scheme / label boundaries, so a strict
6652/// `.computeunit.yaml` shape matches the downstream accepted set
6653/// without case-folding drift (an uppercase `.COMPUTEUNIT.YAML` shape
6654/// that a case-insensitive volume's existence check would match the
6655/// on-disk file would still mismatch the canonical form every in-tree
6656/// `:servicos` fixture and the `Caixa::template` scaffold emit,
6657/// breaking the THEORY.md §V.2.7 render-determinism contract every
6658/// typed slot carries).
6659pub const COMPUTEUNIT_YAML_SUFFIX: &str = ".computeunit.yaml";
6660
6661/// Predicate: assert that `path` terminates in the canonical
6662/// [`COMPUTEUNIT_YAML_SUFFIX`] (lowercase `.computeunit.yaml`) — the
6663/// file-type shape every `:servicos` entry, the ComputeUnit-CR axis
6664/// the M2 typed-substrate caixa-helm / caixa-flux renderers consume
6665/// via `serde_yaml::from_str`, must take. The contract:
6666///
6667///   - the path has a final file-name component (paths ending in `/`
6668///     fail);
6669///   - the file name's UTF-8 string form ends in
6670///     `.computeunit.yaml` — lowercase, no case-folding;
6671///   - at least one byte precedes the suffix (the degenerate hidden-
6672///     file `.computeunit.yaml` shape — file name exactly equal to
6673///     the suffix — fails: the substrate identifies each ComputeUnit
6674///     by the file-stem segment that precedes `.computeunit.yaml`,
6675///     so an empty stem is structurally an unidentified Servico).
6676///
6677/// Returns `true` on accept, `false` on reject. The per-axis caller
6678/// — [`crate::Caixa::validate_code_paths`] on the `:servicos` axis —
6679/// wraps the boolean into its own typed
6680/// `ManifestError::CodePathNonComputeUnitYamlExtension { slot, path }`
6681/// variant so the diagnostic still names the offending slot and the
6682/// offending path verbatim. Peer of [`is_lisp_extension`] on the
6683/// tatara-lisp-source axis (`:bibliotecas` 64772a9); same axis-
6684/// agnostic predicate discipline, here on the compound-suffix axis
6685/// [`Path::extension`] can't express on its own. The third caller —
6686/// the future M2.5 caixa-operator `:servicos` admission webhook
6687/// keying off the same accepted set, the M4
6688/// `mesh.pleme.io/v1alpha1/ComputeUnit` CR materializer's per-
6689/// `:servicos` shape gate, the future `feira fmt`'s `:servicos`
6690/// canonical-form normalizer — lands as a thin wrapper rather than
6691/// re-inlining the same compound-suffix check.
6692///
6693/// Pairs with the per-axis
6694/// [`crate::ManifestError::CodePathNonComputeUnitYamlExtension`]
6695/// variant — that remains the typed surface authors see; this
6696/// predicate is the single-source-of-truth gate the caixa-build
6697/// pipeline consults to produce it.
6698#[must_use]
6699pub fn is_computeunit_yaml_extension(path: &Path) -> bool {
6700    path.file_name()
6701        .and_then(|n| n.to_str())
6702        .is_some_and(|name| {
6703            name.len() > COMPUTEUNIT_YAML_SUFFIX.len() && name.ends_with(COMPUTEUNIT_YAML_SUFFIX)
6704        })
6705}
6706
6707/// Canonical camelCase YAML key for the `:limits` slot's overlay.
6708pub const M2_KEY_LIMITS: &str = "limits";
6709/// Canonical camelCase YAML key for the `:behavior` slot's overlay.
6710pub const M2_KEY_BEHAVIOR: &str = "behavior";
6711/// Canonical camelCase YAML key for the `:upgrade-from` slot's overlay.
6712pub const M2_KEY_UPGRADE_FROM: &str = "upgradeFrom";
6713
6714/// Canonical JSON/YAML top-level key for [`crate::Caixa`]'s runtime
6715/// `deps` axis — the runtime-closure dependency list every build the
6716/// caixa participates in reaches (peer of the dev-only `:deps-dev`
6717/// list [`CAIXA_KEY_DEPS_DEV`] pins). The Rust field is single-word
6718/// `deps`; the `#[serde(rename_all = "camelCase")]` attribute on
6719/// [`crate::Caixa`] is a no-op on this axis (no `_` to transform), so
6720/// the emitted JSON key equals the source-side field name byte-for-byte
6721/// and equals this constant's value.
6722///
6723/// [`crate::Caixa::to_lisp`] threads the manifest through
6724/// `serde_json::to_value(self) → tatara_lisp::domain::json_to_sexp`, so
6725/// the emitted JSON key is the load-bearing byte-string the round-trip
6726/// consumes on its way back to the kebab-case `:deps` author surface.
6727/// Until this lift landed the byte-string `"deps"` was structurally
6728/// implicit in the [`crate::Caixa::deps`] field name at
6729/// [`crate::Caixa`] with no compile-time link to any downstream
6730/// `.get(<key>)` consumer or drift-detection pin — a future
6731/// [`crate::Caixa`] field rename (`deps` → `dependencies` matching
6732/// Cargo's verbatim `[dependencies]` axis, `deps` → `runtime_deps`
6733/// matching a hypothetical per-runtime-target vocabulary flip) OR an
6734/// added `#[serde(rename = "…")]` explicit attribute override (either
6735/// of which would silently break every [`crate::Caixa::to_lisp`]
6736/// round-trip and the future M4 operator-side manifest ingest that
6737/// reaches for `deps` via `Value::get(...)`) would surface at consumer
6738/// parse time as a silently-absent JSON key defaulting to
6739/// [`Vec::new()`], far from the rename's commit and with no field
6740/// naming the drift.
6741///
6742/// Peer of [`CAIXA_KEY_DEPS_DEV`] on the two-list dep-graph
6743/// serialized-key axis: this const names the runtime-closure dep-list
6744/// wire key, [`CAIXA_KEY_DEPS_DEV`] names the dev-only dep-list wire
6745/// key. Byte-identical to the peer [`DEP_AUTHOR_KEY_DEPS`] author-facing
6746/// kebab-case label modulo the leading `:` — the two consts split on
6747/// the axis every dep-graph slot carries (author-facing kebab-case
6748/// label vs. renderer-side wire key). Same "one canonical byte-string
6749/// per typed axis" discipline every peer [`M2_KEY_*`] /
6750/// [`M3_KEY_PLACEMENT`] / [`SUPERVISOR_KEY_*`] const carries.
6751pub const CAIXA_KEY_DEPS: &str = "deps";
6752
6753/// Canonical camelCase JSON/YAML top-level key for [`crate::Caixa`]'s
6754/// `deps_dev` axis — the dev-only dependency list that the M0 base
6755/// package model already exposes (peer of the runtime `:deps` list, but
6756/// excluded from published lacres and consumer builds). The Rust field
6757/// is `snake_case` `deps_dev`; the `#[serde(rename_all = "camelCase")]`
6758/// attribute on [`crate::Caixa`] maps it to the camelCase JSON key
6759/// `"depsDev"` this constant pins.
6760///
6761/// [`crate::Caixa::to_lisp`] threads the manifest through
6762/// `serde_json::to_value(self) → tatara_lisp::domain::json_to_sexp`, so
6763/// the emitted JSON key is the load-bearing byte-string the round-trip
6764/// consumes on its way back to the kebab-case `:deps-dev` author
6765/// surface. Until this lift landed the byte-string `"depsDev"` was
6766/// structurally implicit in the `#[serde(rename_all = "camelCase")]`
6767/// derive attribute at [`crate::Caixa`] with no compile-time link to any
6768/// downstream `.get(<key>)` consumer or drift-detection pin — a future
6769/// [`crate::Caixa`] field rename (`deps_dev` → `dev_deps` matching
6770/// Cargo's verbatim `dev-dependencies` axis, `deps_dev` → `deps_test`
6771/// matching a hypothetical per-test-target vocabulary flip) OR a
6772/// `#[serde(rename_all = "…")]` attribute flip (any of which would
6773/// silently break every `Caixa::to_lisp` round-trip and the future M4
6774/// operator-side manifest ingest that reaches for `depsDev` via
6775/// `Value::get(...)`) would surface at consumer parse time as a
6776/// silently-absent JSON key defaulting to `Vec::new()`, far from the
6777/// rename's commit and with no field naming the drift.
6778///
6779/// Peer of [`M2_KEY_UPGRADE_FROM`] on the sibling top-level
6780/// [`crate::Caixa`] multi-word camelCase-renamed serialized-key axis —
6781/// both are `snake_case → camelCase` renames the `rename_all` derive
6782/// produces on the M0 [`crate::Caixa`] surface. Alongside
6783/// [`SUPERVISOR_KEY_MAX_RESTARTS`] (`"maxRestarts"`, 40cc4e5) and
6784/// [`SUPERVISOR_KEY_RESTART_WINDOW`] (`"restartWindow"`, 40cc4e5) —
6785/// which pin the two supervisor-tree top-level multi-word keys the
6786/// [`crate::Caixa`] surface flattens up — this const closes the last of
6787/// the four multi-word top-level [`crate::Caixa`] serde-derived JSON
6788/// keys still lacking a lifted `&'static str` peer. Same "one canonical
6789/// byte-string per typed serialized-key axis" discipline every peer
6790/// [`M2_KEY_*`] / [`M3_KEY_PLACEMENT`] / [`SUPERVISOR_KEY_*`] const
6791/// carries.
6792pub const CAIXA_KEY_DEPS_DEV: &str = "depsDev";
6793
6794/// Canonical author-facing kebab-case `(defcaixa … :limits (…))` top-level
6795/// slot label the M2 per-Servico Lunatic sandbox `:limits` slot surfaces
6796/// under. Peer of [`M2_KEY_LIMITS`] on the dual-axis pair every M2
6797/// top-level slot carries: the camelCase [`M2_KEY_*`] const names the
6798/// *renderer-side* overlay-container wire key the serde-derive-emitted
6799/// programs.yaml / values.yaml block carries under (`"limits"`, load-bearing
6800/// per the `#[serde(rename_all = "camelCase")]` attribute on the emit-side
6801/// [`servico_m2_overlay`] shape), the kebab-case [`M2_AUTHOR_KEY_*`] const
6802/// names the *author-facing* label the [`crate::Caixa::declared_servico_slots`]
6803/// tagger threads through as one of the `&'static str` entries in the
6804/// canonical-declaration-order slot list every kind-coherence gate consults
6805/// ([`crate::LayoutError::ServicoSlotsOnNonServico`] joins them into the
6806/// space-separated `slots:` diagnostic naming which of the three M2 slots
6807/// the offending caixa declared on a non-Servico kind).
6808///
6809/// Until this lift landed the three kebab-case labels sat once each in
6810/// [`crate::Caixa::declared_servico_slots`] as three-arm inline
6811/// `":limits"` / `":behavior"` / `":upgrade-from"` byte-strings the tagger
6812/// pushed onto its return `Vec`, plus a handful of test-side probe
6813/// literals asserting the diagnostic's `slots:` field carries the
6814/// expected per-arm value verbatim — with no compile-time link between
6815/// the tagger's arms and the tests' expected values. A future rebrand
6816/// (a hypothetical `:limits` → `:sandbox` matching the Lunatic
6817/// terminology INSPIRATIONS §III.1 documents at the per-process level,
6818/// `:behavior` → `:gen-server` matching Erlang's verbatim
6819/// `gen_server` name, `:upgrade-from` → `:appup` matching Erlang's
6820/// verbatim appup terminology, or a per-consumer disambiguation as the
6821/// `defcaixa` macro stabilizes) would silently desynchronize the
6822/// production [`crate::Caixa::declared_servico_slots`] tagger from the
6823/// tests until a downstream consumer surfaced the drift at build time as
6824/// a matches-arm miss far from the rename's commit. This lift closes
6825/// that gap by routing both halves (production tagger + tests) through
6826/// three peer consts declared adjacent to the renderer-side
6827/// [`M2_KEY_*`] peers, so the "one canonical declaration per arm, next
6828/// to the axis" discipline the peer [`M2_BEHAVIOR_AUTHOR_KEY_ON_*`]
6829/// sub-slot author-label consts (889dc18) established for the M2
6830/// `:behavior` sub-slot's per-callback kebab-case labels extends onto
6831/// the M2 top-level slot axis. Same "one canonical byte-string per
6832/// typed axis" discipline every peer M2 / M3 renderer-wire-key axis
6833/// carries ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] /
6834/// [`M2_KEY_UPGRADE_FROM`], [`M2_LIMITS_KEY_MEMORY`] /
6835/// [`M2_LIMITS_KEY_FUEL`] / [`M2_LIMITS_KEY_WALL_CLOCK`] /
6836/// [`M2_LIMITS_KEY_CPU`] (d8b8b4f), [`M2_BEHAVIOR_KEY_ON_INIT`] etc.
6837/// (21fe462), [`M2_UPGRADE_FROM_KEY_FROM`] /
6838/// [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`] (36ffe65)).
6839pub const M2_AUTHOR_KEY_LIMITS: &str = ":limits";
6840/// Canonical author-facing kebab-case `(defcaixa … :behavior (…))`
6841/// top-level slot label the M2 per-Servico OTP-shaped `:behavior`
6842/// gen_server-callback-set slot surfaces under. Peer of
6843/// [`M2_AUTHOR_KEY_LIMITS`] on the sibling M2 top-level slot dual axis;
6844/// see [`M2_AUTHOR_KEY_LIMITS`] for the full lift rationale.
6845pub const M2_AUTHOR_KEY_BEHAVIOR: &str = ":behavior";
6846/// Canonical author-facing kebab-case `(defcaixa … :upgrade-from (…))`
6847/// top-level slot label the M2 per-Servico OTP-appup `:upgrade-from`
6848/// hot-code-reload table slot surfaces under. Peer of
6849/// [`M2_AUTHOR_KEY_LIMITS`] on the sibling M2 top-level slot dual axis;
6850/// see [`M2_AUTHOR_KEY_LIMITS`] for the full lift rationale.
6851pub const M2_AUTHOR_KEY_UPGRADE_FROM: &str = ":upgrade-from";
6852
6853/// Canonical camelCase YAML sub-key the `:limits :memory` per-Servico
6854/// linear-memory-cap scalar-axis lands under inside the [`M2_KEY_LIMITS`]
6855/// overlay block. Peer of [`M2_KEY_LIMITS`] on the sibling `:limits`
6856/// sub-slot axis: `M2_KEY_LIMITS` names the overlay-container's
6857/// top-level key ("limits"), the four `M2_LIMITS_KEY_*` consts name the
6858/// four typed sub-keys ([`LIMITS_MEMORY_WASM32_MAX_BYTES`]-bounded
6859/// memory cap, [`crate::LIMITS_FUEL_MAX`]-bounded fuel budget,
6860/// [`crate::LIMITS_WALL_CLOCK_MAX`]-bounded wall-clock cap,
6861/// [`crate::LIMITS_CPU_MILLICORES_MAX`]-bounded soft cgroup CPU share)
6862/// that the emit-side [`servico_m2_overlay`] serializes through serde
6863/// (`LimitsSpec` carries `#[serde(rename_all = "camelCase")]`) and every
6864/// substrate-side test-side navigator probes to pin the round-trip
6865/// through the rendered `programs.yaml` per-Servico entry / lareira
6866/// chart `values.yaml` per-`pleme-computeunit` block. The lower-camel
6867/// shape (`"memory"` / `"fuel"` / `"wallClock"` / `"cpu"`) is
6868/// load-bearing: the serde-derive on [`crate::LimitsSpec`] emits under
6869/// the same shape and the drift-detection pin in `limits.rs::tests`
6870/// (`limits_spec_serde_keys_match_lifted_m2_limits_key_consts`)
6871/// serializes a fully-populated [`crate::LimitsSpec`] and asserts each
6872/// canonical `M2_LIMITS_KEY_*` byte-sequence appears in the JSON — so a
6873/// hypothetical future `rename_all = "snake_case"` / `"kebab-case"`
6874/// accident at the derive attribute surfaces as a build-time test
6875/// failure at `limits.rs` rather than as a silent test-side
6876/// `.get(<stale-camelCase-const>)` returning `None` far from the
6877/// derive-attr drift's commit. Same "one canonical byte-string per
6878/// typed axis" discipline every peer M2 / M3 wire-key axis carries
6879/// ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`],
6880/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.).
6881pub const M2_LIMITS_KEY_MEMORY: &str = "memory";
6882/// Canonical camelCase YAML sub-key the `:limits :fuel` per-Servico
6883/// wasm-instruction-budget scalar-axis lands under inside the
6884/// [`M2_KEY_LIMITS`] overlay block. Peer of [`M2_LIMITS_KEY_MEMORY`] on
6885/// the sibling `:limits` sub-slot axis.
6886pub const M2_LIMITS_KEY_FUEL: &str = "fuel";
6887/// Canonical camelCase YAML sub-key the `:limits :wall-clock` per-Servico
6888/// wall-clock-cap scalar-axis lands under inside the [`M2_KEY_LIMITS`]
6889/// overlay block. Peer of [`M2_LIMITS_KEY_MEMORY`] on the sibling
6890/// `:limits` sub-slot axis; the camelCase shape (`"wallClock"`, not
6891/// `"wall_clock"`) is load-bearing per the serde-derive attribute on
6892/// [`crate::LimitsSpec`].
6893pub const M2_LIMITS_KEY_WALL_CLOCK: &str = "wallClock";
6894/// Canonical camelCase YAML sub-key the `:limits :cpu` per-Servico
6895/// soft-cgroup-CPU-share millicores scalar-axis lands under inside the
6896/// [`M2_KEY_LIMITS`] overlay block. Peer of [`M2_LIMITS_KEY_MEMORY`] on
6897/// the sibling `:limits` sub-slot axis.
6898pub const M2_LIMITS_KEY_CPU: &str = "cpu";
6899
6900/// Canonical camelCase YAML sub-key the `:behavior :on-init` per-Servico
6901/// OTP-shaped instance-init-callback path scalar-axis lands under inside
6902/// the [`M2_KEY_BEHAVIOR`] overlay block. Peer of [`M2_KEY_BEHAVIOR`] on
6903/// the sibling `:behavior` sub-slot axis: [`M2_KEY_BEHAVIOR`] names the
6904/// overlay-container's top-level key ("behavior"), the six
6905/// `M2_BEHAVIOR_KEY_ON_*` consts name the six typed sub-keys the M2
6906/// [`crate::BehaviorSpec`] struct's OTP-shaped callback fields
6907/// (`on_init` / `on_call` / `on_cast` / `on_info` / `on_state_change` /
6908/// `on_terminate`, analogs of `gen_server:init/1` / `handle_call/3` /
6909/// `handle_cast/2` / `handle_info/2` / `code_change/3` / `terminate/2`
6910/// per `theory/INSPIRATIONS.md` §II.3) serialize as under the
6911/// `#[serde(rename_all = "camelCase")]` derive attribute
6912/// (`"onInit"` / `"onCall"` / `"onCast"` / `"onInfo"` / `"onStateChange"`
6913/// / `"onTerminate"`). Emitted by [`servico_m2_overlay`] as sub-keys of
6914/// the [`M2_KEY_BEHAVIOR`] overlay block and consumed by every
6915/// substrate-side test-side navigator that reaches into the rendered
6916/// `programs.yaml` per-Servico entry / lareira chart `values.yaml`
6917/// per-`pleme-computeunit` block to pin the per-callback round-trip.
6918/// The lower-camel shape is load-bearing: the serde-derive on
6919/// [`crate::BehaviorSpec`] emits under the same shape and the
6920/// drift-detection pin in `behavior.rs::tests`
6921/// (`behavior_spec_serde_keys_match_lifted_m2_behavior_key_consts`)
6922/// serializes a fully-populated [`crate::BehaviorSpec`] and asserts each
6923/// canonical `M2_BEHAVIOR_KEY_ON_*` byte-sequence appears in the JSON —
6924/// so a hypothetical future `rename_all = "snake_case"` / `"kebab-case"`
6925/// accident at the derive attribute or an OTP-lineage per-callback
6926/// rebrand (`:on-init` → `:on-start` matching Akka's per-actor
6927/// preStart naming, `:on-call` → `:on-request` matching a hypothetical
6928/// wasi:http/incoming-handler terminology flip, `:on-state-change` →
6929/// `:on-code-change` matching Erlang's verbatim `code_change/3` name)
6930/// coordinated at the type's derive attribute surfaces as a build-time
6931/// test failure at `behavior.rs` rather than as a silent test-side
6932/// `.get(<stale-camelCase-const>)` returning `None` far from the
6933/// derive-attr drift's commit. Same "one canonical byte-string per typed
6934/// axis" discipline every peer M2 / M3 wire-key axis carries
6935/// ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`],
6936/// [`M2_LIMITS_KEY_MEMORY`] / [`M2_LIMITS_KEY_FUEL`] /
6937/// [`M2_LIMITS_KEY_WALL_CLOCK`] / [`M2_LIMITS_KEY_CPU`] (d8b8b4f),
6938/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.).
6939pub const M2_BEHAVIOR_KEY_ON_INIT: &str = "onInit";
6940/// Canonical camelCase YAML sub-key the `:behavior :on-call` per-Servico
6941/// OTP-shaped sync-request-handler path scalar-axis lands under inside
6942/// the [`M2_KEY_BEHAVIOR`] overlay block. Peer of
6943/// [`M2_BEHAVIOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot axis.
6944pub const M2_BEHAVIOR_KEY_ON_CALL: &str = "onCall";
6945/// Canonical camelCase YAML sub-key the `:behavior :on-cast` per-Servico
6946/// OTP-shaped async-fire-and-forget-handler path scalar-axis lands under
6947/// inside the [`M2_KEY_BEHAVIOR`] overlay block. Peer of
6948/// [`M2_BEHAVIOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot axis.
6949pub const M2_BEHAVIOR_KEY_ON_CAST: &str = "onCast";
6950/// Canonical camelCase YAML sub-key the `:behavior :on-info` per-Servico
6951/// OTP-shaped out-of-band-message-handler path scalar-axis lands under
6952/// inside the [`M2_KEY_BEHAVIOR`] overlay block. Peer of
6953/// [`M2_BEHAVIOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot axis.
6954pub const M2_BEHAVIOR_KEY_ON_INFO: &str = "onInfo";
6955/// Canonical camelCase YAML sub-key the `:behavior :on-state-change`
6956/// per-Servico OTP-shaped hot-upgrade state-migration path scalar-axis
6957/// lands under inside the [`M2_KEY_BEHAVIOR`] overlay block. Peer of
6958/// [`M2_BEHAVIOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot axis;
6959/// the camelCase shape (`"onStateChange"`, not `"on_state_change"`) is
6960/// load-bearing per the serde-derive attribute on
6961/// [`crate::BehaviorSpec`].
6962pub const M2_BEHAVIOR_KEY_ON_STATE_CHANGE: &str = "onStateChange";
6963/// Canonical camelCase YAML sub-key the `:behavior :on-terminate`
6964/// per-Servico OTP-shaped graceful-shutdown-callback path scalar-axis
6965/// lands under inside the [`M2_KEY_BEHAVIOR`] overlay block. Peer of
6966/// [`M2_BEHAVIOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot axis.
6967pub const M2_BEHAVIOR_KEY_ON_TERMINATE: &str = "onTerminate";
6968
6969/// Canonical author-facing kebab-case `(defcaixa … :behavior (:on-init …))`
6970/// slot label the `:behavior :on-init` per-Servico OTP-shaped instance-init
6971/// callback axis surfaces under. Peer of [`M2_BEHAVIOR_KEY_ON_INIT`] on the
6972/// dual-axis pair every M2 `:behavior` sub-slot carries: the camelCase
6973/// [`M2_BEHAVIOR_KEY_ON_*`] const names the *renderer-side* wire key the
6974/// serde-derive-emitted [`M2_KEY_BEHAVIOR`] overlay carries under
6975/// (`"onInit"` etc, load-bearing per the `#[serde(rename_all = "camelCase")]`
6976/// attribute on [`crate::BehaviorSpec`]), the kebab-case
6977/// [`M2_BEHAVIOR_AUTHOR_KEY_ON_*`] const names the *author-facing* label the
6978/// [`crate::BehaviorSpec::declared_slots`] tagger threads through as the
6979/// `slot: &'static str` field on every [`crate::BehaviorError`] variant
6980/// (`":on-init"` etc, the exact byte-string authors see in the
6981/// per-slot value-shape diagnostic naming which of the six typed callback
6982/// slots the offending path landed on).
6983///
6984/// Until this lift landed the six kebab-case labels sat once each in
6985/// [`crate::BehaviorSpec::declared_slots`] as the six-arm inline
6986/// `":on-init"` / `":on-call"` / `":on-cast"` / `":on-info"` /
6987/// `":on-state-change"` / `":on-terminate"` byte-strings the tagger
6988/// iterated over, plus roughly two dozen test-side probe literals
6989/// asserting the diagnostic's `slot:` field carries the expected
6990/// per-arm value verbatim — with no compile-time link between the
6991/// tagger's arms and the tests' expected values. A future OTP-lineage
6992/// per-callback rebrand (`:on-init` → `:on-start` matching Akka's
6993/// per-actor preStart naming, `:on-call` → `:on-request` matching a
6994/// hypothetical wasi:http/incoming-handler terminology flip,
6995/// `:on-state-change` → `:on-code-change` matching Erlang's verbatim
6996/// `code_change/3` name, `:on-terminate` → `:on-shutdown` matching a
6997/// generic-lifecycle rebrand) or a per-consumer disambiguation (a
6998/// vocabulary shift on the author surface as the `defcaixa` macro
6999/// stabilizes) would silently desynchronize the production
7000/// [`crate::BehaviorSpec::declared_slots`] tagger from the tests until
7001/// a downstream consumer surfaced the drift at build time as a
7002/// matches-arm miss. This lift closes that gap by routing both halves
7003/// (production tagger + tests) through six peer consts declared
7004/// adjacent to the renderer-side [`M2_BEHAVIOR_KEY_ON_*`] peers, so
7005/// the "one canonical declaration per arm, next to the axis" discipline
7006/// the [`WitTarget::HTTP_FIELD_NAME`] / [`WitTarget::PUBSUB_FIELD_NAME`]
7007/// / [`WitTarget::STORE_FIELD_NAME`] payload-arm peer consts (174e96a)
7008/// already established for the [`crate::WitContract::target`]'s per-arm
7009/// diagnostic-scalar axis extends onto the M2 `:behavior` sub-slot
7010/// author-facing-label axis. Same "one canonical byte-string per typed
7011/// axis" discipline every peer M2 / M3 wire-key axis carries
7012/// ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`],
7013/// [`M2_LIMITS_KEY_MEMORY`] / [`M2_LIMITS_KEY_FUEL`] /
7014/// [`M2_LIMITS_KEY_WALL_CLOCK`] / [`M2_LIMITS_KEY_CPU`] (d8b8b4f),
7015/// [`M2_BEHAVIOR_KEY_ON_INIT`] / [`M2_BEHAVIOR_KEY_ON_CALL`] /
7016/// [`M2_BEHAVIOR_KEY_ON_CAST`] / [`M2_BEHAVIOR_KEY_ON_INFO`] /
7017/// [`M2_BEHAVIOR_KEY_ON_STATE_CHANGE`] / [`M2_BEHAVIOR_KEY_ON_TERMINATE`]
7018/// (21fe462), [`M2_UPGRADE_FROM_KEY_FROM`] /
7019/// [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`] (36ffe65),
7020/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.), extended here to close the
7021/// M2 `:behavior` sub-slot's *author-facing-label* axis so the same
7022/// discipline the renderer-side wire-key axis carries applies to the
7023/// author-facing side.
7024pub const M2_BEHAVIOR_AUTHOR_KEY_ON_INIT: &str = ":on-init";
7025/// Canonical author-facing kebab-case `(defcaixa … :behavior (:on-call …))`
7026/// slot label for the `:behavior :on-call` per-Servico OTP-shaped
7027/// synchronous request/response handler axis. Peer of
7028/// [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot
7029/// author-facing-label axis.
7030pub const M2_BEHAVIOR_AUTHOR_KEY_ON_CALL: &str = ":on-call";
7031/// Canonical author-facing kebab-case `(defcaixa … :behavior (:on-cast …))`
7032/// slot label for the `:behavior :on-cast` per-Servico OTP-shaped
7033/// asynchronous fire-and-forget handler axis. Peer of
7034/// [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot
7035/// author-facing-label axis.
7036pub const M2_BEHAVIOR_AUTHOR_KEY_ON_CAST: &str = ":on-cast";
7037/// Canonical author-facing kebab-case `(defcaixa … :behavior (:on-info …))`
7038/// slot label for the `:behavior :on-info` per-Servico OTP-shaped
7039/// out-of-band message handler axis. Peer of
7040/// [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`] on the sibling `:behavior` sub-slot
7041/// author-facing-label axis.
7042pub const M2_BEHAVIOR_AUTHOR_KEY_ON_INFO: &str = ":on-info";
7043/// Canonical author-facing kebab-case
7044/// `(defcaixa … :behavior (:on-state-change …))` slot label for the
7045/// `:behavior :on-state-change` per-Servico OTP-shaped hot-upgrade
7046/// state-migration axis. Peer of [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`] on the
7047/// sibling `:behavior` sub-slot author-facing-label axis; the kebab-case
7048/// shape (`":on-state-change"`, not `":on-statechange"` /
7049/// `":on_state_change"`) is load-bearing per the author-facing
7050/// `(defcaixa …)` macro's canonical form and the exact byte-string the
7051/// per-slot [`crate::BehaviorError`] diagnostic threads through.
7052pub const M2_BEHAVIOR_AUTHOR_KEY_ON_STATE_CHANGE: &str = ":on-state-change";
7053/// Canonical author-facing kebab-case
7054/// `(defcaixa … :behavior (:on-terminate …))` slot label for the
7055/// `:behavior :on-terminate` per-Servico OTP-shaped graceful-shutdown
7056/// callback axis. Peer of [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`] on the sibling
7057/// `:behavior` sub-slot author-facing-label axis.
7058pub const M2_BEHAVIOR_AUTHOR_KEY_ON_TERMINATE: &str = ":on-terminate";
7059
7060/// Canonical camelCase YAML sub-key the `:upgrade-from :from` per-entry
7061/// OTP-appup-shaped prior-`:versao` semver-string scalar-axis lands under
7062/// inside each element of the [`M2_KEY_UPGRADE_FROM`] overlay sequence.
7063/// Peer of [`M2_KEY_UPGRADE_FROM`] on the sibling `:upgrade-from` sub-slot
7064/// axis: [`M2_KEY_UPGRADE_FROM`] names the overlay-container's top-level
7065/// key ("upgradeFrom"), the two `M2_UPGRADE_FROM_KEY_*` consts name the
7066/// two typed sub-keys the M2 [`crate::UpgradeFromEntry`] struct's
7067/// OTP-appup-shaped per-entry fields (`from` semver-of-the-prior-`:versao`
7068/// / `instructions` typed [`crate::UpgradeInstruction`] list, analogs of
7069/// the OTP `.appup` file's `{FromVsn, [Instruction, …]}` per-entry tuple
7070/// per `theory/INSPIRATIONS.md` §II.4) serialize as under the
7071/// `#[serde(rename_all = "camelCase")]` derive attribute (`"from"` /
7072/// `"instructions"`). Emitted by [`servico_m2_overlay`] as sub-keys of
7073/// each element of the [`M2_KEY_UPGRADE_FROM`] overlay sequence and
7074/// consumed by every substrate-side test-side navigator that reaches into
7075/// the rendered `programs.yaml` per-Servico entry / lareira chart
7076/// `values.yaml` per-`pleme-computeunit` block to pin the per-entry
7077/// round-trip. The lower-camel shape (`"from"` / `"instructions"`) is
7078/// load-bearing: the serde-derive on [`crate::UpgradeFromEntry`] emits
7079/// under the same shape and the drift-detection pin in
7080/// `upgrade.rs::tests`
7081/// (`upgrade_from_entry_serde_keys_match_lifted_m2_upgrade_from_key_consts`)
7082/// serializes a fully-populated [`crate::UpgradeFromEntry`] and asserts
7083/// each canonical `M2_UPGRADE_FROM_KEY_*` byte-sequence appears in the
7084/// JSON — so a hypothetical future `rename_all = "snake_case"` /
7085/// `"kebab-case"` accident at the derive attribute or an OTP-lineage
7086/// per-entry-key rebrand (`:from` → `:prior-versao` matching a hypothetical
7087/// verbatim-Erlang `FromVsn` collapse, `:instructions` → `:steps` matching
7088/// a hypothetical Akka appup-shape rebrand) coordinated at the type's
7089/// derive attribute surfaces as a build-time test failure at `upgrade.rs`
7090/// rather than as a silent test-side `.get(<stale-camelCase-const>)`
7091/// returning `None` far from the derive-attr drift's commit. Same "one
7092/// canonical byte-string per typed axis" discipline every peer M2 / M3
7093/// wire-key axis carries ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] /
7094/// [`M2_KEY_UPGRADE_FROM`], [`M2_LIMITS_KEY_MEMORY`] /
7095/// [`M2_LIMITS_KEY_FUEL`] / [`M2_LIMITS_KEY_WALL_CLOCK`] /
7096/// [`M2_LIMITS_KEY_CPU`] (d8b8b4f), [`M2_BEHAVIOR_KEY_ON_INIT`] /
7097/// [`M2_BEHAVIOR_KEY_ON_CALL`] / [`M2_BEHAVIOR_KEY_ON_CAST`] /
7098/// [`M2_BEHAVIOR_KEY_ON_INFO`] / [`M2_BEHAVIOR_KEY_ON_STATE_CHANGE`] /
7099/// [`M2_BEHAVIOR_KEY_ON_TERMINATE`] (21fe462),
7100/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.). Closes the M2 sub-slot camelCase
7101/// key axis: with this lift the three M2 typed slots (`:limits` /
7102/// `:behavior` / `:upgrade-from`) all have their canonical camelCase
7103/// sub-slot key constants pinned into caixa-core.
7104pub const M2_UPGRADE_FROM_KEY_FROM: &str = "from";
7105/// Canonical camelCase YAML sub-key the `:upgrade-from :instructions`
7106/// per-entry OTP-appup-shaped typed [`crate::UpgradeInstruction`] list
7107/// axis lands under inside each element of the [`M2_KEY_UPGRADE_FROM`]
7108/// overlay sequence. Peer of [`M2_UPGRADE_FROM_KEY_FROM`] on the sibling
7109/// `:upgrade-from` sub-slot axis.
7110pub const M2_UPGRADE_FROM_KEY_INSTRUCTIONS: &str = "instructions";
7111
7112/// Canonical `#[serde(tag = "…")]` discriminator-key byte-sequence the
7113/// M2 `:upgrade-from :instructions` per-entry OTP-appup
7114/// [`crate::UpgradeInstruction`] enum surfaces its variant tag under
7115/// on serde emission — the internally-tagged wire key downstream
7116/// consumers navigate to (`serde_json::to_value(&instr).get("kind")`
7117/// / `serde_yaml::Value::Mapping.get("kind")` / hand-authored `{"kind":
7118/// "load-module", "module": "…"}` JSON) to disambiguate which of the
7119/// five OTP-shaped variants they hold. The `#[serde(tag = "kind",
7120/// rename_all = "kebab-case")]` attribute on
7121/// [`crate::UpgradeInstruction`] emits exactly this byte-sequence as
7122/// the tag-slot key, and this const names the same byte-string one
7123/// altitude above the derive attribute so every downstream consumer
7124/// that reaches for the tag (the reflection-vs-serde round-trip check
7125/// in [`caixa-core/tests/dispatcher_registration.rs`] that probes
7126/// `v.get("kind")` against every variant's expected kebab-case tag,
7127/// the future M4 `mesh.pleme.io/v1alpha1/Caixa` CR materializer's
7128/// upgrade-instruction admission webhook, any wasm-operator dispatch
7129/// step that navigates the serialized instruction blob to route by
7130/// variant) routes through one canonical `&'static str` rather than
7131/// re-inlining the literal.
7132///
7133/// Lifted as a typed `pub const` (rather than an inline literal at
7134/// the `#[serde(tag = "…")]` attribute site + every consumer probe)
7135/// so the tag-key axis has exactly one source of truth — a future
7136/// serde-shape rebrand (`tag = "kind"` → `tag = "type"` matching a
7137/// JSON-Schema `discriminator` convention, `tag = "kind"` → `tag = "op"`
7138/// matching a hypothetical OTP-abbreviation collapse, `tag = "kind"`
7139/// → `tag = "instruction"` matching a hypothetical author-surface
7140/// self-description flip as the `defcaixa` macro stabilizes) lands as
7141/// an edit to exactly one const, and every consumer that reaches for
7142/// the tag picks it up at build time rather than at runtime as a
7143/// silent `.get(<stale-tag-key>)` returning `None` far from the
7144/// derive-attr drift's commit. Same "one canonical byte-string per
7145/// typed axis" discipline every peer M2 sub-slot wire-key axis
7146/// carries ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] /
7147/// [`M2_KEY_UPGRADE_FROM`], [`M2_LIMITS_KEY_MEMORY`] etc. (d8b8b4f),
7148/// [`M2_BEHAVIOR_KEY_ON_INIT`] etc. (21fe462),
7149/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
7150/// (36ffe65)), now extending the lift onto the last remaining
7151/// un-lifted wire-key axis on the M2 `:upgrade-from :instructions`
7152/// typed slot: the internally-tagged variant-discriminator key that
7153/// pairs with the [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] etc.
7154/// (56120ef) per-variant kebab-case *values* the same
7155/// `#[serde(tag = "kind", rename_all = "kebab-case")]` attribute
7156/// emits. With this lift the `:upgrade-from :instructions` axis has
7157/// its dual (`key = "kind"` + five variant-value tags) fully lifted
7158/// into caixa-core.
7159pub const M2_UPGRADE_INSTRUCTION_KEY_KIND: &str = "kind";
7160
7161/// Canonical per-variant data-field JSON key the M2 `:upgrade-from
7162/// :instructions` per-entry OTP-appup
7163/// [`crate::UpgradeInstruction::LoadModule`] / [`crate::UpgradeInstruction::SoftPurge`]
7164/// / [`crate::UpgradeInstruction::Purge`] variants surface their
7165/// module-name payload under on serde emission — the internally-tagged
7166/// per-variant field byte-string every downstream consumer reading the
7167/// module string reaches for
7168/// (`serde_json::to_value(&instr).get("module")` /
7169/// `serde_yaml::Value::Mapping.get("module")` / hand-authored
7170/// `{"kind": "load-module", "module": "hello-rio"}` JSON blobs the
7171/// wasm-operator's upgrade-dispatch step consumes to route the
7172/// per-module load / soft-purge / purge action). The three variants
7173/// carrying a `module: String` field
7174/// ([`crate::UpgradeInstruction::LoadModule`], [`crate::UpgradeInstruction::SoftPurge`],
7175/// [`crate::UpgradeInstruction::Purge`]) all emit this exact
7176/// byte-sequence as the data-field JSON key alongside the
7177/// [`M2_UPGRADE_INSTRUCTION_KEY_KIND`] tag-key on the same instruction
7178/// blob — the `#[serde(tag = "kind", rename_all = "kebab-case")]`
7179/// attribute on [`crate::UpgradeInstruction`] promotes each variant's
7180/// struct-field name to a sibling JSON key at the same nesting level as
7181/// the tag, so a `LoadModule { module: "hello-rio" }` serializes to
7182/// `{"kind": "load-module", "module": "hello-rio"}` — one tag axis, one
7183/// data-field axis, both live on the same JSON object and both must be
7184/// pinned into caixa-core so a future rebrand at either axis surfaces
7185/// as a build-time test failure rather than an apply-time
7186/// `.get(<stale-field-key>)` returning `None` far from the field-name
7187/// drift's commit.
7188///
7189/// Lifted as a typed `pub const` (rather than an inline literal at every
7190/// consumer probe) so the per-variant module-field axis has exactly one
7191/// source of truth — a future struct-field rebrand (`module: String` →
7192/// `component: String` matching a hypothetical WASI component-model
7193/// naming pass, `module: String` → `name: String` matching the
7194/// canonical `KUBE_KEY_NAME` axis, `module: String` → `target: String`
7195/// matching the sibling `:contratos :para` axis) lands as an edit to
7196/// exactly one const, and every consumer that probes the module-field
7197/// key picks it up at build time. Same "one canonical byte-string per
7198/// typed axis" discipline the sibling
7199/// [`M2_UPGRADE_INSTRUCTION_KEY_KIND`] (6a203d7) lift established on
7200/// the peer tag-slot key axis on the same
7201/// [`crate::UpgradeInstruction`] enum: `KEY_KIND` names the tag axis,
7202/// `FIELD_KEY_MODULE` names the module-payload axis, and the two must
7203/// be disjoint by construction (an internally-tagged serialization
7204/// where the tag key collides with a data-field key silently corrupts
7205/// every serialized blob — same failure mode
7206/// `m2_upgrade_instruction_key_kind_const_disjoint_from_variant_data_keys`
7207/// pins on the sibling axis).
7208///
7209/// With this lift and its [`M2_UPGRADE_INSTRUCTION_FIELD_KEY_SCRIPT`]
7210/// peer, the whole `:upgrade-from :instructions` variant-JSON dual is
7211/// lifted into caixa-core: the tag *key*
7212/// ([`M2_UPGRADE_INSTRUCTION_KEY_KIND`]), the five tag *values*
7213/// ([`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] etc.), and the two
7214/// data-field *keys* (this const and `SCRIPT`) all sit as
7215/// single-source-of-truth `&'static str`s. Any future serde-shape
7216/// rebrand touching either axis (tag key rename, per-variant field
7217/// rename, `rename_all` regime flip) surfaces at build time.
7218pub const M2_UPGRADE_INSTRUCTION_FIELD_KEY_MODULE: &str = "module";
7219
7220/// Canonical per-variant data-field JSON key the M2 `:upgrade-from
7221/// :instructions` per-entry [`crate::UpgradeInstruction::StateChange`]
7222/// variant surfaces its script-path payload under on serde emission —
7223/// the internally-tagged per-variant field byte-string every downstream
7224/// consumer reading the migration-script path reaches for
7225/// (`serde_json::to_value(&instr).get("script")` /
7226/// `serde_yaml::Value::Mapping.get("script")` / hand-authored
7227/// `{"kind": "state-change", "script": "lib/migrations/v01-to-v02.lisp"}`
7228/// JSON blobs the wasm-operator's upgrade-dispatch step consumes to
7229/// route the per-`gen_server` `code_change/3` migration action). Peer
7230/// of [`M2_UPGRADE_INSTRUCTION_FIELD_KEY_MODULE`] on the sibling
7231/// module-payload axis; see [`M2_UPGRADE_INSTRUCTION_FIELD_KEY_MODULE`]
7232/// for the full lift rationale.
7233///
7234/// The [`crate::UpgradeInstruction::StateChange`] variant is the only
7235/// one carrying a `script: PathBuf` field — the two module-bearing
7236/// variants ([`crate::UpgradeInstruction::LoadModule`],
7237/// [`crate::UpgradeInstruction::SoftPurge`],
7238/// [`crate::UpgradeInstruction::Purge`]) route through the sibling
7239/// [`M2_UPGRADE_INSTRUCTION_FIELD_KEY_MODULE`] const, and
7240/// [`crate::UpgradeInstruction::Restart`] carries no data field at all.
7241/// Same one-const-per-typed-axis discipline as the sibling.
7242pub const M2_UPGRADE_INSTRUCTION_FIELD_KEY_SCRIPT: &str = "script";
7243
7244/// Canonical author-facing kebab-case tag the M2 `:upgrade-from
7245/// :instructions` per-entry OTP-appup [`crate::UpgradeInstruction::LoadModule`]
7246/// variant surfaces under — the `:kind` field the
7247/// [`crate::UpgradeError::ModuleEmpty`] / [`crate::UpgradeError::ModuleInvalid`]
7248/// / [`crate::UpgradeError::DuplicateCleanup`] / [`crate::UpgradeError::PurgeWithoutPriorLoad`]
7249/// diagnostics carry so the author can grep their caixa.lisp for
7250/// `(:load-module …)` and fix it in one edit. The
7251/// [`crate::UpgradeInstruction::lisp_form`] production dispatch and every
7252/// test-side probe that pins a `kind:` / `kinds:` / `other_kinds:` /
7253/// `prior_cleanup_kind:` field routes through this const, so a future
7254/// per-variant kebab-case rebrand (`:load-module` → `:load` matching a
7255/// hypothetical Erlang `code:load_module` collapse, `:load-module` →
7256/// `:reload` matching a hypothetical Elixir/Phoenix hot-reload rebrand,
7257/// or a per-consumer disambiguation as the `defcaixa` macro stabilizes)
7258/// lands at one const-edit per arm and reaches both surfaces
7259/// (production dispatch + tests) by construction. Peer of
7260/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
7261/// on the sibling `:upgrade-from` sub-slot renderer-wire-key axis
7262/// (36ffe65) — this const family extends the same "one canonical
7263/// byte-string per typed axis" discipline onto the *author-facing*
7264/// per-instruction-variant tag axis one altitude below the
7265/// `:instructions` container. Same "one canonical declaration per arm,
7266/// next to the axis" discipline the peer [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`]
7267/// etc. (889dc18) established for the M2 `:behavior` sub-slot's
7268/// per-callback kebab-case labels, [`CONTRATO_AUTHOR_KEY_DE`] /
7269/// [`CONTRATO_AUTHOR_KEY_PARA`] (f50c875) for the M3 `:contratos`
7270/// per-entry endpoint labels, and every top-level [`M2_AUTHOR_KEY_LIMITS`]
7271/// (f49c8b0) / [`M3_AUTHOR_KEY_MEMBROS`] (882f498) /
7272/// [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] (be40492) family established.
7273pub const M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE: &str = ":load-module";
7274/// Canonical author-facing kebab-case tag the M2 `:upgrade-from
7275/// :instructions` per-entry [`crate::UpgradeInstruction::StateChange`]
7276/// variant surfaces under. Peer of [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`]
7277/// on the sibling per-instruction-variant tag axis; see
7278/// [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] for the full lift rationale.
7279pub const M2_UPGRADE_INSTRUCTION_KIND_STATE_CHANGE: &str = ":state-change";
7280/// Canonical author-facing kebab-case tag the M2 `:upgrade-from
7281/// :instructions` per-entry [`crate::UpgradeInstruction::SoftPurge`]
7282/// variant surfaces under. Peer of [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`]
7283/// on the sibling per-instruction-variant tag axis; see
7284/// [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] for the full lift rationale.
7285pub const M2_UPGRADE_INSTRUCTION_KIND_SOFT_PURGE: &str = ":soft-purge";
7286/// Canonical author-facing kebab-case tag the M2 `:upgrade-from
7287/// :instructions` per-entry [`crate::UpgradeInstruction::Purge`]
7288/// variant surfaces under. Peer of [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`]
7289/// on the sibling per-instruction-variant tag axis; see
7290/// [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] for the full lift rationale.
7291pub const M2_UPGRADE_INSTRUCTION_KIND_PURGE: &str = ":purge";
7292/// Canonical author-facing kebab-case tag the M2 `:upgrade-from
7293/// :instructions` per-entry [`crate::UpgradeInstruction::Restart`]
7294/// variant surfaces under. Peer of [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`]
7295/// on the sibling per-instruction-variant tag axis; see
7296/// [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] for the full lift rationale.
7297pub const M2_UPGRADE_INSTRUCTION_KIND_RESTART: &str = ":restart";
7298
7299/// Canonical lowercase JSON/YAML discriminator-key the
7300/// [`crate::dep::DepSource`] enum's `#[serde(tag = "tipo", rename_all
7301/// = "lowercase")]` derive emits as the tag axis at each serialized
7302/// `Dep.fonte` block — the load-bearing byte-string every downstream
7303/// consumer reading a Dep source (the [`caixa_resolver`] per-`:deps`
7304/// git-clone dispatcher, the future `feira lock` / `feira resolve`
7305/// `lacre.lisp` closure writer, every test payload that reaches
7306/// `Value::get(DEP_SOURCE_KEY_TIPO)` to pin the variant discriminator)
7307/// must probe on. Peer of the two variant tag consts
7308/// [`DEP_SOURCE_TIPO_GIT`] and [`DEP_SOURCE_TIPO_PATH`] the sibling
7309/// `rename_all = "lowercase"` axis lifts on the same discriminator
7310/// block: the [`DEP_SOURCE_KEY_TIPO`] const names the outer tag *key*
7311/// (`"tipo":`) the `tag = "tipo"` attribute pins, the two
7312/// `DEP_SOURCE_TIPO_*` consts name the two admitted tag *values*
7313/// (`"git"` / `"path"`) the `rename_all = "lowercase"` attribute pins
7314/// as the discriminator's closed-set arms.
7315///
7316/// Until this lift landed the two load-bearing bytes at both altitudes
7317/// (`"tipo"` at the tag key, `"git"` / `"path"` at the two variant
7318/// tags) sat only as inline literals — at the `#[serde(tag = "tipo",
7319/// rename_all = "lowercase")]` attribute (dep.rs:59) and at one
7320/// round-trip test payload (`git_source_json_round_trip` pinning
7321/// `"tipo":"git"` inline, dep.rs:13563) — with no compile-time link
7322/// between the load-bearing serde-derive attribute and the downstream
7323/// consumers that probe the emit-side discriminator via
7324/// `Value::get(...)`. A future accidental `tag = "type"` /
7325/// `tag = "source_type"` typo at the attribute (English-uniformity
7326/// rebrand as the substrate publishes its typed manifest schema
7327/// outside pleme-io, verbatim-Cargo `"type"` alignment matching a
7328/// hypothetical Zig-store convergence, or per-consumer disambiguation
7329/// as the `defcaixa` macro stabilizes) — or a `rename_all` rebrand
7330/// (`"UPPERCASE"` / `"snake_case"` / `"kebab-case"`) — would silently
7331/// break the resolver's `Dep.fonte` dispatch and every downstream
7332/// `lacre.lisp` closure consumer, with the drift surfacing at fetch
7333/// time far from the derive-attr commit as an unknown-variant deserialize
7334/// failure. Pinning the three canonical byte-sequences to `&'static str`
7335/// consts + running the serialize-and-check drift-detection pins on
7336/// both variants closes the drift structurally at caixa-core build time.
7337///
7338/// Same "one canonical byte-string per typed serialized-key axis"
7339/// discipline the peer [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] etc.
7340/// (56120ef), [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`] etc., and
7341/// [`HELM_CHART_TYPE_APPLICATION`] / [`HELM_CHART_TYPE_LIBRARY`]
7342/// (1c5eb9d) closed-set variant-tag lifts carry — extended here to the
7343/// [`crate::dep::DepSource`] `:deps :fonte` typed slot's discriminator
7344/// axis at both altitudes (discriminator key + closed-set variant tags),
7345/// the last `#[serde(tag = ..., rename_all = ...)]` discriminator
7346/// family in caixa-core lacking a lifted peer.
7347pub const DEP_SOURCE_KEY_TIPO: &str = "tipo";
7348/// Canonical lowercase JSON/YAML discriminator-value the
7349/// [`crate::dep::DepSource::Git`] variant surfaces under — the
7350/// `"git"` scalar the `#[serde(tag = "tipo", rename_all =
7351/// "lowercase")]` derive emits at the [`DEP_SOURCE_KEY_TIPO`] axis
7352/// for the Git arm. Peer of [`DEP_SOURCE_TIPO_PATH`] on the sibling
7353/// closed-set variant-tag axis; see [`DEP_SOURCE_KEY_TIPO`] for the
7354/// full lift rationale. The scalar is derived from the Rust variant
7355/// name `Git` by the `rename_all = "lowercase"` derive; ASCII-lowercase
7356/// of `Git` is `git`.
7357pub const DEP_SOURCE_TIPO_GIT: &str = "git";
7358/// Canonical lowercase JSON/YAML discriminator-value the
7359/// [`crate::dep::DepSource::Path`] variant surfaces under — the
7360/// `"path"` scalar the `#[serde(tag = "tipo", rename_all =
7361/// "lowercase")]` derive emits at the [`DEP_SOURCE_KEY_TIPO`] axis
7362/// for the Path arm. Peer of [`DEP_SOURCE_TIPO_GIT`] on the sibling
7363/// closed-set variant-tag axis; see [`DEP_SOURCE_KEY_TIPO`] for the
7364/// full lift rationale.
7365///
7366/// Byte-identical to [`CILIUM_KEY_PATH`], [`FLUX_KUSTOMIZATION_KEY_PATH`],
7367/// and [`GATEWAY_API_KEY_PATH`] today — all four resolve to the same
7368/// four-byte `"path"` literal — but semantically distinct: the three
7369/// `*_KEY_PATH` consts name YAML container/leaf-*key* axes on their
7370/// respective K8s CR schemas (Cilium L7 HTTP-rule filesystem-path
7371/// container, Flux Kustomization git-source-subtree container, Gateway
7372/// API URL-path-match container), while this constant names a
7373/// discriminator *value* on the manifest-side [`crate::dep::DepSource`]
7374/// typed enum's closed-set variant tag axis (Path variant vs Git
7375/// variant). Splitting the four lets each axis's future rebrand land
7376/// independently at its canonical const definition without coupling
7377/// the `:deps :fonte` Path-variant discriminator axis to the three
7378/// K8s-CR key axes (or vice versa) — same
7379/// "byte-identical-but-semantically-distinct" discipline the peer
7380/// [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`] and
7381/// [`FLEET_PROGRAMS_KEY_VERSAO`] / [`MEMBRO_KEY_VERSAO`] splits
7382/// established on the sibling per-entry key axes.
7383pub const DEP_SOURCE_TIPO_PATH: &str = "path";
7384
7385/// Canonical [`crate::LayoutError::MissingEntry`] `kind: &'static str`
7386/// discriminator scalar the M2 `:behavior` typed slot's per-callback
7387/// on-disk-leaf existence gate surfaces under — the byte-string every
7388/// [`crate::LayoutInvariants::verify`] emission carries when a
7389/// `:behavior :on-init` / `:on-call` / `:on-cast` / `:on-info` /
7390/// `:on-state-change` / `:on-terminate` sub-slot's tatara-lisp source
7391/// path fails to resolve against the caixa root's on-disk layout. Names
7392/// the "M2 :behavior sub-slot leaf-kind" axis one altitude below the
7393/// [`M2_AUTHOR_KEY_BEHAVIOR`] (f49c8b0) parent-slot label: the
7394/// top-level [`M2_AUTHOR_KEY_BEHAVIOR`] const names the M2 slot itself
7395/// on the author surface (`(defcaixa … :behavior (…))`), the six
7396/// [`M2_BEHAVIOR_AUTHOR_KEY_ON_*`] consts (889dc18) name the per-
7397/// callback sub-slot labels the author writes (`(:on-init "lib/init.lisp"
7398/// …)`), and this const names the per-slot-family leaf-kind byte-string
7399/// the layout diagnostic emits when the on-disk `lib/init.lisp` file
7400/// doesn't exist ("MissingEntry { kind: \"behavior-callback\", path:
7401/// /root/lib/init.lisp }").
7402///
7403/// Peer of [`LAYOUT_MISSING_ENTRY_KIND_UPGRADE_SCRIPT`] on the sibling
7404/// M2 `:upgrade-from` typed slot's per-entry leaf-kind axis: the two
7405/// consts split the M2 slot-family's on-disk-leaf categorization axis
7406/// into its two per-slot arms, so the `LayoutError::MissingEntry
7407/// { kind: &'static str, .. }` discriminator's accept-set has one
7408/// canonical declaration per arm rather than two inline byte-strings
7409/// scattered across [`crate::layout`]'s per-slot existence gates.
7410///
7411/// Until this lift landed the byte `"behavior-callback"` sat at two
7412/// sites in [`crate::layout`] — once at the [`crate::LayoutInvariants::verify`]
7413/// per-`:behavior :on-*` sub-slot existence gate's `MissingEntry` emit
7414/// (production, layout.rs:902), once at the
7415/// [`crate::layout::tests::behavior_callback_must_exist`]
7416/// (or peer test) `matches!(…, MissingEntry { kind: "behavior-callback",
7417/// .. })` shape probe (layout.rs:3152) — with no compile-time link
7418/// between the two: a future per-consumer rebrand (a hypothetical
7419/// `"behavior-callback"` → `"m2-behavior-callback"` for altitude-explicit
7420/// scoping as the M3+ layout gates grow their own per-slot leaf-kind
7421/// labels, `"behavior-callback"` → `"gen-server-callback"` matching a
7422/// verbatim-OTP rebrand of the [`M2_AUTHOR_KEY_BEHAVIOR`] slot's
7423/// `gen_server`-lineage identity, or a per-diagnostic disambiguation as
7424/// the `defcaixa` macro stabilizes and per-callback shapes diverge)
7425/// would silently desynchronize the production `MissingEntry` emission
7426/// from the test's `matches!` shape probe until build time surfaced the
7427/// drift as a pattern-arm miss far from the rename's commit. This lift
7428/// closes that gap by routing both halves (production emit + test
7429/// probe) through one peer const declared adjacent to the M2 top-level
7430/// slot-label family, so the "one canonical declaration per arm, next
7431/// to the axis" discipline the peer [`M2_AUTHOR_KEY_LIMITS`] /
7432/// [`M2_AUTHOR_KEY_BEHAVIOR`] / [`M2_AUTHOR_KEY_UPGRADE_FROM`]
7433/// (f49c8b0), [`M2_BEHAVIOR_AUTHOR_KEY_ON_INIT`] etc. (889dc18),
7434/// [`M2_UPGRADE_INSTRUCTION_KIND_LOAD_MODULE`] etc. (56120ef),
7435/// [`M3_AUTHOR_KEY_MEMBROS`] etc. (882f498), and
7436/// [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] etc. (be40492) top-level +
7437/// sub-slot author-facing-label consts established for the sibling
7438/// M2 / M3 / Supervisor slot-family axes extends onto the M2
7439/// layout-check leaf-kind categorization axis.
7440///
7441/// Byte-shape note: unlike the peer author-facing kebab-case slot
7442/// labels (which carry the leading `:` sigil because the tatara-lisp
7443/// reader emits keyword tokens as `:kebab-case` and the author writes
7444/// them verbatim in `caixa.lisp`), this discriminator has no leading
7445/// `:` because the substrate consumer reading the value is the layout
7446/// diagnostic's downstream printer — the operator running `feira build`
7447/// sees `LayoutError::MissingEntry { kind: "behavior-callback", .. }`
7448/// as a categorization label, not as a tatara-lisp keyword to be
7449/// grep'd for in the source `.lisp`. Same shape distinction the peer
7450/// [`crate::WitTarget::HTTP_FIELD_NAME`] (= `"endpoint"`) /
7451/// [`crate::WitTarget::PUBSUB_FIELD_NAME`] (= `"subject"`) /
7452/// [`crate::WitTarget::STORE_FIELD_NAME`] (= `"slot"`) /
7453/// [`crate::WitTarget::CAPABILITY_EXPECTED`] (= `"none"`) consts
7454/// established on the sibling `:contratos` per-entry payload-field-
7455/// name axis: the field-name byte-strings are the downstream
7456/// diagnostic's format-argument scalars, prefixed by the `:` inside
7457/// the error format template (`":{expected}"`) rather than baked into
7458/// the const.
7459pub const LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK: &str = "behavior-callback";
7460
7461/// Canonical [`crate::LayoutError::MissingEntry`] `kind: &'static str`
7462/// discriminator scalar the M2 `:upgrade-from` typed slot's per-entry
7463/// [`crate::UpgradeInstruction::StateChange`] script-path on-disk-leaf
7464/// existence gate surfaces under — the byte-string every
7465/// [`crate::LayoutInvariants::verify`] emission carries when a
7466/// `(:state-change "<script>.lisp")` instruction's tatara-lisp source
7467/// path fails to resolve against the caixa root's on-disk layout.
7468/// Peer of [`LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`] on the sibling
7469/// M2 `:behavior` typed slot's per-callback leaf-kind axis; see
7470/// [`LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`] for the full lift
7471/// rationale.
7472pub const LAYOUT_MISSING_ENTRY_KIND_UPGRADE_SCRIPT: &str = "upgrade-script";
7473
7474/// Canonical [`crate::LayoutError::MissingEntry`] `kind: &'static str`
7475/// discriminator scalar the M0 `:kind Biblioteca` typed slot's
7476/// per-`:bibliotecas` entry on-disk-leaf existence gate surfaces under
7477/// — the byte-string every [`crate::LayoutInvariants::verify`]
7478/// emission carries when a `:bibliotecas ("lib/foo.lisp" …)` entry's
7479/// tatara-lisp source path fails to resolve against the caixa root's
7480/// on-disk layout. Peer of [`LAYOUT_MISSING_ENTRY_KIND_EXE`] /
7481/// [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`] on the sibling M0 code-slot
7482/// per-directory leaf-kind axes, and of the M2-tier
7483/// [`LAYOUT_MISSING_ENTRY_KIND_BEHAVIOR_CALLBACK`] /
7484/// [`LAYOUT_MISSING_ENTRY_KIND_UPGRADE_SCRIPT`] (95c9c4c) leaf-kind
7485/// labels on the [`crate::LayoutError::MissingEntry`] `kind:
7486/// &'static str` discriminator's accept-set — completes the
7487/// M0-tier arm of the same per-slot leaf-kind categorization axis
7488/// the M2 lift established.
7489///
7490/// Byte-identical to [`crate::CaixaKind::Biblioteca`]'s
7491/// [`crate::CaixaKind::as_str`] output today (both resolve to the
7492/// same eleven-byte `"biblioteca"` scalar) — the pin test
7493/// `layout_missing_entry_kind_m0_consts_align_with_caixa_kind_as_str`
7494/// makes the coincidence load-bearing rather than accidental so a
7495/// future rename that touches either axis (a per-consumer
7496/// disambiguation as the layout diagnostic vocabulary sharpens, a
7497/// verbatim-Portuguese rebrand of the [`crate::CaixaKind`]'s
7498/// human-readable-form arm) has to reach both sites in lockstep
7499/// or the pin trips at build time.
7500pub const LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA: &str = "biblioteca";
7501
7502/// Canonical [`crate::LayoutError::MissingEntry`] `kind: &'static str`
7503/// discriminator scalar the M0 `:kind Binario` typed slot's per-`:exe`
7504/// entry on-disk-leaf existence gate surfaces under — the byte-string
7505/// every [`crate::LayoutInvariants::verify`] emission carries when an
7506/// `:exe ("exe/tool.lisp" …)` entry's tatara-lisp source path fails to
7507/// resolve against the caixa root's on-disk layout. Peer of
7508/// [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] /
7509/// [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`] on the sibling M0 code-slot
7510/// per-directory leaf-kind axes; see
7511/// [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] for the shared lift
7512/// rationale.
7513///
7514/// Semantically distinct from [`crate::CaixaKind::Binario`]'s
7515/// [`crate::CaixaKind::as_str`] output (`"binario"`) — this const
7516/// names the *directory-entry* leaf-kind label (the M0 `:exe`
7517/// per-entry axis carries source files under the `exe/` subtree),
7518/// not the caixa's own [`crate::CaixaKind`] discriminator. The
7519/// [`crate::LayoutError::MissingEntry`] `kind` emission consumer
7520/// (the operator running `feira build`) reads this as a per-directory
7521/// categorization label (`"missing exe/... entry"`), whereas
7522/// [`crate::CaixaKind::as_str`] names the whole caixa's runtime kind
7523/// (`"binario"` = "this caixa produces one or more binaries"). Two
7524/// axes, two lifts — the pin test
7525/// `layout_missing_entry_kind_m0_consts_align_with_caixa_kind_as_str`
7526/// asserts the *inequality* between this const and
7527/// [`crate::CaixaKind::Binario`]'s [`crate::CaixaKind::as_str`]
7528/// output, so a future accidental collapse of the two axes onto a
7529/// single scalar surfaces at build time.
7530pub const LAYOUT_MISSING_ENTRY_KIND_EXE: &str = "exe";
7531
7532/// Canonical [`crate::LayoutError::MissingEntry`] `kind: &'static str`
7533/// discriminator scalar the M0 `:kind Servico` typed slot's
7534/// per-`:servicos` entry on-disk-leaf existence gate surfaces under —
7535/// the byte-string every [`crate::LayoutInvariants::verify`] emission
7536/// carries when a `:servicos ("servicos/foo.computeunit.yaml" …)`
7537/// entry fails to resolve against the caixa root's on-disk layout.
7538/// Peer of [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] /
7539/// [`LAYOUT_MISSING_ENTRY_KIND_EXE`] on the sibling M0 code-slot
7540/// per-directory leaf-kind axes; see
7541/// [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] for the shared lift
7542/// rationale. Byte-identical to [`crate::CaixaKind::Servico`]'s
7543/// [`crate::CaixaKind::as_str`] output today (both resolve to the
7544/// same seven-byte `"servico"` scalar).
7545pub const LAYOUT_MISSING_ENTRY_KIND_SERVICO: &str = "servico";
7546
7547/// Canonical human-readable label the M0 [`crate::CaixaKind::Biblioteca`]
7548/// arm surfaces under [`crate::CaixaKind::as_str`] and (routed through
7549/// it) [`std::fmt::Display`] — the byte-string every future diagnostic
7550/// / graph / audit consumer that formats a `:kind` variant as
7551/// user-facing text lands on (the future wasm-operator's per-caixa
7552/// startup log line naming the loaded caixa's typed shape, the future
7553/// `feira app graph` per-member kind column, the future M4
7554/// `wasm.pleme.io/v1alpha1/ComputeUnit` / `mesh.pleme.io/v1alpha1/*` CR
7555/// materializer's admission-webhook rejection body naming which typed
7556/// kind the offending manifest carries). Peer of the sibling four
7557/// [`CAIXA_KIND_LABEL_BINARIO`] / [`CAIXA_KIND_LABEL_SERVICO`] /
7558/// [`CAIXA_KIND_LABEL_SUPERVISOR`] / [`CAIXA_KIND_LABEL_APLICACAO`]
7559/// consts on the same closed [`crate::CaixaKind`] enum surface —
7560/// together the pentad names every author-reachable arm of the
7561/// substrate's most fundamental typed axis (what a caixa produces),
7562/// mirroring the closed-enum-scalar-value trajectory the sibling
7563/// OTP-shaped [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] etc. (09ffb2d) and
7564/// [`SUPERVISOR_CHILD_RESTART_PERMANENT`] etc. (ccdf955) and the M3
7565/// [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`] etc. (3f0e21c) established
7566/// on the sibling closed-set typed-enum discriminator axes.
7567///
7568/// Until this lift landed the five [`crate::CaixaKind::as_str`] arms
7569/// each returned a hand-authored byte-string literal (`"biblioteca"`
7570/// / `"binario"` / `"servico"` / `"supervisor"` / `"aplicacao"`) at
7571/// the source-side match arm with no compile-time link to the peer
7572/// [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] /
7573/// [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`] consts on the sibling
7574/// layout-diagnostic axis (whose bytes coincide by design), and no
7575/// [`std::fmt::Display`] surface at all — every consumer reaching for
7576/// a caixa-kind byte-string past the wire format
7577/// (`Serialize` → PascalCase `"Biblioteca"` etc.) had to reach for the
7578/// hand-authored [`crate::CaixaKind::as_str`] arm's literal or roll a
7579/// per-consumer `format!("{v:?}")` `Debug` route, either of which a
7580/// future variant rename would silently desynchronize. Lifting the
7581/// five arms onto peer consts + routing [`std::fmt::Display`] through
7582/// [`crate::CaixaKind::as_str`] closes the drift footgun structurally:
7583/// the human-readable byte-string (`Display` + `as_str`), the wire
7584/// byte-string (`Serialize`, PascalCase — intentionally distinct from
7585/// the human-readable form), and the layout-diagnostic byte-string
7586/// (`LAYOUT_MISSING_ENTRY_KIND_*`) each route through one canonical
7587/// declaration per axis, with pin tests
7588/// (`caixa_kind_as_str_returns_lifted_peer_const`,
7589/// `caixa_kind_display_routes_through_as_str_helper`) making any drift
7590/// a caixa-core-build-time failure.
7591///
7592/// Byte-identical to [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] today
7593/// (both resolve to the same eleven-byte `"biblioteca"` scalar) — the
7594/// pin test
7595/// [`layout_missing_entry_kind_m0_consts_align_with_caixa_kind_as_str`]
7596/// (fe2a898) already made the coincidence load-bearing on the sibling
7597/// layout-leaf-kind axis. Semantically distinct: this const names the
7598/// [`crate::CaixaKind`] discriminator's human-readable form (the
7599/// substrate's canonical `:kind` label), while
7600/// [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] names the
7601/// [`crate::LayoutError::MissingEntry`] `kind: &'static str`
7602/// leaf-kind discriminator (the per-`:bibliotecas`-entry on-disk-leaf
7603/// existence diagnostic's categorization label). Two axes, two lifts —
7604/// same "byte-identical-but-semantically-distinct" discipline the peer
7605/// [`FLEET_PROGRAMS_KEY_VERSAO`] / [`MEMBRO_KEY_VERSAO`] split (ce80ca0)
7606/// established on the sibling per-entry version-constraint axis.
7607pub const CAIXA_KIND_LABEL_BIBLIOTECA: &str = "biblioteca";
7608
7609/// Canonical human-readable label the M0 [`crate::CaixaKind::Binario`]
7610/// arm surfaces under [`crate::CaixaKind::as_str`] and (routed through
7611/// it) [`std::fmt::Display`]. Peer of [`CAIXA_KIND_LABEL_BIBLIOTECA`] /
7612/// [`CAIXA_KIND_LABEL_SERVICO`] / [`CAIXA_KIND_LABEL_SUPERVISOR`] /
7613/// [`CAIXA_KIND_LABEL_APLICACAO`] on the same closed
7614/// [`crate::CaixaKind`] enum surface; see [`CAIXA_KIND_LABEL_BIBLIOTECA`]
7615/// for the shared lift rationale.
7616///
7617/// Semantically distinct from [`LAYOUT_MISSING_ENTRY_KIND_EXE`]
7618/// (`"exe"`) — the alignment pin
7619/// [`layout_missing_entry_kind_m0_consts_align_with_caixa_kind_as_str`]
7620/// (fe2a898) asserts the *inequality* between the layout-side leaf-kind
7621/// label (which names the `exe/` directory sub-tree) and this
7622/// [`crate::CaixaKind`] discriminator label (which names the caixa's
7623/// whole runtime kind). Two axes, two lifts.
7624pub const CAIXA_KIND_LABEL_BINARIO: &str = "binario";
7625
7626/// Canonical human-readable label the M0 [`crate::CaixaKind::Servico`]
7627/// arm surfaces under [`crate::CaixaKind::as_str`] and (routed through
7628/// it) [`std::fmt::Display`]. Peer of [`CAIXA_KIND_LABEL_BIBLIOTECA`] /
7629/// [`CAIXA_KIND_LABEL_BINARIO`] / [`CAIXA_KIND_LABEL_SUPERVISOR`] /
7630/// [`CAIXA_KIND_LABEL_APLICACAO`] on the same closed
7631/// [`crate::CaixaKind`] enum surface; see [`CAIXA_KIND_LABEL_BIBLIOTECA`]
7632/// for the shared lift rationale.
7633///
7634/// Byte-identical to [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`] today (both
7635/// resolve to the same seven-byte `"servico"` scalar) — the pin test
7636/// [`layout_missing_entry_kind_m0_consts_align_with_caixa_kind_as_str`]
7637/// (fe2a898) already made the coincidence load-bearing on the sibling
7638/// layout-leaf-kind axis. Semantically distinct: this const names the
7639/// [`crate::CaixaKind`] discriminator's human-readable form (the
7640/// substrate's canonical `:kind Servico` label), while
7641/// [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`] names the per-`:servicos`-entry
7642/// on-disk-leaf existence diagnostic's categorization label.
7643pub const CAIXA_KIND_LABEL_SERVICO: &str = "servico";
7644
7645/// Canonical human-readable label the M2 [`crate::CaixaKind::Supervisor`]
7646/// arm surfaces under [`crate::CaixaKind::as_str`] and (routed through
7647/// it) [`std::fmt::Display`]. Peer of [`CAIXA_KIND_LABEL_BIBLIOTECA`] /
7648/// [`CAIXA_KIND_LABEL_BINARIO`] / [`CAIXA_KIND_LABEL_SERVICO`] /
7649/// [`CAIXA_KIND_LABEL_APLICACAO`] on the same closed
7650/// [`crate::CaixaKind`] enum surface; see [`CAIXA_KIND_LABEL_BIBLIOTECA`]
7651/// for the shared lift rationale.
7652///
7653/// No layout-leaf-kind peer today — the `:kind Supervisor` typed slot
7654/// carries no on-disk source-file sub-tree (a supervisor is composed
7655/// entirely of `:children` references to other caixas), so no
7656/// [`crate::LayoutError::MissingEntry`] `kind:` diagnostic reaches for
7657/// this label. The const stands as the sole source of truth for the
7658/// [`crate::CaixaKind::Supervisor`] arm's human-readable form.
7659pub const CAIXA_KIND_LABEL_SUPERVISOR: &str = "supervisor";
7660
7661/// Canonical human-readable label the M3 [`crate::CaixaKind::Aplicacao`]
7662/// arm surfaces under [`crate::CaixaKind::as_str`] and (routed through
7663/// it) [`std::fmt::Display`]. Peer of [`CAIXA_KIND_LABEL_BIBLIOTECA`] /
7664/// [`CAIXA_KIND_LABEL_BINARIO`] / [`CAIXA_KIND_LABEL_SERVICO`] /
7665/// [`CAIXA_KIND_LABEL_SUPERVISOR`] on the same closed
7666/// [`crate::CaixaKind`] enum surface; see [`CAIXA_KIND_LABEL_BIBLIOTECA`]
7667/// for the shared lift rationale.
7668///
7669/// Byte-identical to [`FLEET_PROGRAMS_KEY_APLICACAO`] today (both
7670/// resolve to the same nine-byte `"aplicacao"` scalar) — the coincidence
7671/// is deliberate but semantically distinct: this const names the
7672/// [`crate::CaixaKind::Aplicacao`] discriminator's human-readable form
7673/// (the substrate's canonical `:kind Aplicacao` label), while
7674/// [`FLEET_PROGRAMS_KEY_APLICACAO`] names the per-programs.yaml-entry
7675/// passthrough-annotation YAML key that links a member entry back to
7676/// its parent Aplicacao (MESH-COMPOSITION §III.4). Two axes, two lifts
7677/// — same "byte-identical-but-semantically-distinct" discipline every
7678/// peer split establishes.
7679pub const CAIXA_KIND_LABEL_APLICACAO: &str = "aplicacao";
7680
7681/// Canonical human-readable label the [`crate::CaixaKind::Acao`] arm
7682/// surfaces under [`crate::CaixaKind::as_str`] and (routed through it)
7683/// [`std::fmt::Display`]. Sixth peer of [`CAIXA_KIND_LABEL_BIBLIOTECA`] /
7684/// [`CAIXA_KIND_LABEL_BINARIO`] / [`CAIXA_KIND_LABEL_SERVICO`] /
7685/// [`CAIXA_KIND_LABEL_SUPERVISOR`] / [`CAIXA_KIND_LABEL_APLICACAO`] on
7686/// the same closed [`crate::CaixaKind`] enum surface; see
7687/// [`CAIXA_KIND_LABEL_BIBLIOTECA`] for the shared lift rationale.
7688///
7689/// No layout-leaf-kind peer today (mirroring [`CAIXA_KIND_LABEL_SUPERVISOR`])
7690/// — the `:kind Acao` slot's sole payload is the `:ci` field
7691/// (a `canteiro_types::CiRun`), which is not a code-surface
7692/// path-existence check the way `:bibliotecas`/`:exe`/`:servicos` are.
7693pub const CAIXA_KIND_LABEL_ACAO: &str = "acao";
7694
7695/// Canonical PascalCase wire byte-string the [`crate::CaixaKind::Biblioteca`]
7696/// arm serializes as under the un-`rename`d `#[derive(Serialize)]` on
7697/// [`crate::CaixaKind`] — the exact byte-shape every wire surface that
7698/// carries a Caixa's `:kind` outside the caixa-core boundary consumes
7699/// (the [`caixa_crd::caixa_cr::CaixaSpec`] `kind:` field the K8s
7700/// `Caixa` CR persists between apply and reconcile passes, the
7701/// tatara-lisp author-surface `:kind Biblioteca` symbol the sexp parser
7702/// binds into the typed [`crate::CaixaKind`] enum, the future M4
7703/// `mesh.pleme.io/v1alpha1/Caixa` CR materializer's per-CR admission-
7704/// webhook wire binding).
7705///
7706/// Peer of the sibling [`CAIXA_KIND_LABEL_BIBLIOTECA`] lowercase-Portuguese
7707/// diagnostic-form const on the sibling axis — the two byte-strings are
7708/// *intentionally distinct* by design (see the two-axis-split docstring
7709/// on [`crate::CaixaKind::as_str`] + the load-bearing pin
7710/// [`crate::kind::tests::caixa_kind_display_matches_as_str_and_not_serialize_wire`]
7711/// on the split). This wire const names the substrate's PascalCase
7712/// wire form; the sibling `_LABEL_*` const names the substrate's
7713/// lowercase-Portuguese diagnostic form. Six-arm parallel of the
7714/// same closed [`crate::CaixaKind`] enum surface — same "one canonical
7715/// byte-string per arm, per axis, next to the axis" discipline every
7716/// peer typed-enum const family carries.
7717///
7718/// Prior to this lift, every consumer that needed the PascalCase wire
7719/// byte-shape reached for one of two fragile paths: `format!("{:?}",
7720/// kind)` (couples the wire format to `Debug`'s stability guarantee,
7721/// which is *no guarantee at all* by Rust's own conventions — a
7722/// `#[derive(Debug)]` swap for a hand-rolled `impl Debug` that pretty-
7723/// prints the variant with extra context is a permitted mechanical
7724/// edit whose apply-time symptom would be every downstream K8s CR
7725/// carrying a stale wire byte-string), or `serde_json::to_string(&k)`
7726/// then string-trim of the outer quotes (introduces an allocation +
7727/// error-handling path for a byte-shape the compiler knows verbatim at
7728/// build time). Lifting the six arms onto peer consts routes the
7729/// substrate's wire byte-shape through one canonical declaration per
7730/// arm the paired [`crate::CaixaKind::wire_name`] +
7731/// [`crate::CaixaKind::from_wire`] typed dispatch consumers key off.
7732pub const CAIXA_KIND_WIRE_BIBLIOTECA: &str = "Biblioteca";
7733
7734/// Canonical PascalCase wire byte-string the [`crate::CaixaKind::Binario`]
7735/// arm serializes as under the un-`rename`d `#[derive(Serialize)]` on
7736/// [`crate::CaixaKind`]. Peer of [`CAIXA_KIND_WIRE_BIBLIOTECA`] on the
7737/// same closed [`crate::CaixaKind`] enum surface; see the sibling
7738/// [`CAIXA_KIND_WIRE_BIBLIOTECA`] docstring for the shared lift
7739/// rationale.
7740pub const CAIXA_KIND_WIRE_BINARIO: &str = "Binario";
7741
7742/// Canonical PascalCase wire byte-string the [`crate::CaixaKind::Servico`]
7743/// arm serializes as under the un-`rename`d `#[derive(Serialize)]` on
7744/// [`crate::CaixaKind`]. Peer of [`CAIXA_KIND_WIRE_BIBLIOTECA`] on the
7745/// same closed [`crate::CaixaKind`] enum surface; see the sibling
7746/// [`CAIXA_KIND_WIRE_BIBLIOTECA`] docstring for the shared lift
7747/// rationale.
7748pub const CAIXA_KIND_WIRE_SERVICO: &str = "Servico";
7749
7750/// Canonical PascalCase wire byte-string the [`crate::CaixaKind::Supervisor`]
7751/// arm serializes as under the un-`rename`d `#[derive(Serialize)]` on
7752/// [`crate::CaixaKind`]. Peer of [`CAIXA_KIND_WIRE_BIBLIOTECA`] on the
7753/// same closed [`crate::CaixaKind`] enum surface; see the sibling
7754/// [`CAIXA_KIND_WIRE_BIBLIOTECA`] docstring for the shared lift
7755/// rationale.
7756pub const CAIXA_KIND_WIRE_SUPERVISOR: &str = "Supervisor";
7757
7758/// Canonical PascalCase wire byte-string the [`crate::CaixaKind::Aplicacao`]
7759/// arm serializes as under the un-`rename`d `#[derive(Serialize)]` on
7760/// [`crate::CaixaKind`]. Peer of [`CAIXA_KIND_WIRE_BIBLIOTECA`] on the
7761/// same closed [`crate::CaixaKind`] enum surface; see the sibling
7762/// [`CAIXA_KIND_WIRE_BIBLIOTECA`] docstring for the shared lift
7763/// rationale.
7764pub const CAIXA_KIND_WIRE_APLICACAO: &str = "Aplicacao";
7765
7766/// Canonical PascalCase wire byte-string the [`crate::CaixaKind::Acao`]
7767/// arm serializes as under the un-`rename`d `#[derive(Serialize)]` on
7768/// [`crate::CaixaKind`]. Sixth peer of [`CAIXA_KIND_WIRE_BIBLIOTECA`] /
7769/// [`CAIXA_KIND_WIRE_BINARIO`] / [`CAIXA_KIND_WIRE_SERVICO`] /
7770/// [`CAIXA_KIND_WIRE_SUPERVISOR`] / [`CAIXA_KIND_WIRE_APLICACAO`] on
7771/// the same closed [`crate::CaixaKind`] enum surface; see the sibling
7772/// [`CAIXA_KIND_WIRE_BIBLIOTECA`] docstring for the shared lift
7773/// rationale.
7774pub const CAIXA_KIND_WIRE_ACAO: &str = "Acao";
7775
7776/// Canonical caixa-root-relative directory name housing every
7777/// [`crate::CaixaKind::Biblioteca`] caixa's `lib/<nome>.lisp` entry
7778/// (and every `:bibliotecas ("lib/foo.lisp" …)` per-entry source
7779/// path the M0 `:kind Biblioteca` typed slot admits). The single
7780/// source of truth every consumer that composes a caixa-root-relative
7781/// path pointing at the tatara-lisp library sub-tree reaches for:
7782///
7783///   - [`crate::LayoutInvariants::verify`] joins `root` with this
7784///     const to reconstruct the default `lib/<nome>.lisp` per-caixa
7785///     entry the [`crate::LayoutError::MissingLib`] emission gates on;
7786///   - `feira init`'s new-caixa scaffolder joins `root` with this
7787///     const to seed the empty `lib/` sub-tree the template's
7788///     `lib/<nome>.lisp` starter file lives in;
7789///   - `feira fmt` / `feira lint` enumerate every `.lisp` under
7790///     `root.join(LAYOUT_DIR_LIB)` as their default target set (their
7791///     `--paths`-less invocation walks the library sub-tree the
7792///     substrate's [`crate::LayoutInvariants::verify`] pins);
7793///   - `feira tofu` reads every `.lisp` under `root.join(LAYOUT_DIR_LIB)`
7794///     to concatenate the `(defteia …)` forms the caixa-arch invariants
7795///     bind on.
7796///
7797/// The `lib/` byte-shape is a Cargo-style abbreviation of the M0
7798/// `:kind Biblioteca` discriminator ([`crate::CaixaKind::Biblioteca`]
7799/// / [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`], both `"biblioteca"`),
7800/// deliberately distinct from the discriminator's byte-shape so the
7801/// on-disk convention stays terse while the diagnostic label stays
7802/// full-form Portuguese. Peer of [`LAYOUT_DIR_EXE`] /
7803/// [`LAYOUT_DIR_SERVICOS`] on the sibling M0 per-`CaixaKind`
7804/// on-disk-directory-name axes — the three consts jointly single-source
7805/// the CSE-invariant layout convention every caixa the substrate accepts
7806/// carries. A future rebrand of the on-disk directory landing convention
7807/// (`"lib"` → `"src"` matching Rust's convention, `"lib"` → `"biblioteca"`
7808/// matching the full-form Portuguese-uniformity a per-kind consumer
7809/// disambiguation would prefer) lands as a one-line const-edit + the
7810/// paired drift-detection pin that guards the two-axis distinctness
7811/// (`layout_dir_bib_is_distinct_from_layout_missing_entry_kind_bib`)
7812/// rather than a coordinated ~40-site sweep across production +
7813/// tests + CI scaffolders.
7814///
7815/// Same "one canonical byte-string per typed axis + a paired
7816/// drift-detection pin at every load-bearing byte-shape coincidence"
7817/// discipline the M0 [`LAYOUT_MISSING_ENTRY_KIND_BIBLIOTECA`] /
7818/// [`LAYOUT_MISSING_ENTRY_KIND_EXE`] / [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`]
7819/// (fe2a898) leaf-kind categorization triad established on the peer
7820/// [`crate::LayoutError::MissingEntry`] `kind:` discriminator axis.
7821pub const LAYOUT_DIR_LIB: &str = "lib";
7822
7823/// Canonical caixa-root-relative directory name housing every
7824/// [`crate::CaixaKind::Binario`] caixa's `exe/<name>` entry (and
7825/// every `:exe ("exe/tool" …)` per-entry source path the M0
7826/// `:kind Binario` typed slot admits). Peer of [`LAYOUT_DIR_LIB`] /
7827/// [`LAYOUT_DIR_SERVICOS`] on the sibling M0 per-`CaixaKind`
7828/// on-disk-directory-name axes; see [`LAYOUT_DIR_LIB`] for the
7829/// shared lift rationale.
7830///
7831/// [`crate::LayoutInvariants::verify`] joins `root` with this const
7832/// to reconstruct the sandbox-root the [`crate::LayoutError::ExeOutsideDir`]
7833/// emission gates every declared `:exe` entry against — a `:exe`
7834/// entry whose resolved path escapes `root.join(LAYOUT_DIR_EXE)`
7835/// surfaces `ExeOutsideDir(<path>)` at `feira build` time rather than
7836/// silently reaching outside the caixa's sandbox at OCI-build /
7837/// nix-build time. Byte-identical (by design) to
7838/// [`LAYOUT_MISSING_ENTRY_KIND_EXE`] — the M0 `:kind Binario`
7839/// on-disk-directory-name and the [`crate::LayoutError::MissingEntry`]
7840/// `kind:` leaf-kind categorization label share the same three-byte
7841/// scalar because both name the same axis (the `exe/` sub-tree), a
7842/// coincidence the pin test
7843/// `layout_dir_exe_matches_layout_missing_entry_kind_exe` makes
7844/// load-bearing so a rebrand touching either axis without the other
7845/// trips at build time rather than surfacing at
7846/// [`crate::LayoutInvariants::verify`] time as a mismatched
7847/// `MissingEntry.kind` diagnostic naming a stale label.
7848pub const LAYOUT_DIR_EXE: &str = "exe";
7849
7850/// Canonical caixa-root-relative directory name housing every
7851/// [`crate::CaixaKind::Servico`] caixa's
7852/// `servicos/<nome>.computeunit.yaml` per-CR `ComputeUnit` descriptor
7853/// (and every `:servicos ("servicos/foo.computeunit.yaml" …)`
7854/// per-entry source path the M0 `:kind Servico` typed slot admits).
7855/// Peer of [`LAYOUT_DIR_LIB`] / [`LAYOUT_DIR_EXE`] on the sibling M0
7856/// per-`CaixaKind` on-disk-directory-name axes; see [`LAYOUT_DIR_LIB`]
7857/// for the shared lift rationale.
7858///
7859/// [`crate::LayoutInvariants::verify`] joins `root` with this const
7860/// to reconstruct the sandbox-root the
7861/// [`crate::LayoutError::ServicoOutsideDir`] emission gates every
7862/// declared `:servicos` entry against — a `:servicos` entry whose
7863/// resolved path escapes `root.join(LAYOUT_DIR_SERVICOS)` surfaces
7864/// `ServicoOutsideDir(<path>)` at `feira build` time rather than
7865/// silently reaching outside the caixa's sandbox at
7866/// [`caixa_helm`][ch] / [`caixa_flux`][cf] render time or at the
7867/// operator's OCI-build step.
7868///
7869/// The `servicos/` byte-shape is the Portuguese *plural* of the M0
7870/// `:kind Servico` discriminator ([`crate::CaixaKind::Servico`] /
7871/// [`LAYOUT_MISSING_ENTRY_KIND_SERVICO`], both `"servico"`, singular)
7872/// — the on-disk directory holds one-or-more `ComputeUnit` YAML
7873/// descriptors per caixa, the discriminator names the caixa's kind.
7874/// The pin test
7875/// `layout_dir_servicos_is_distinct_from_layout_missing_entry_kind_servico`
7876/// makes the singular/plural split load-bearing so a future rebrand
7877/// touching either axis without the other (a per-consumer
7878/// disambiguation collapsing them, a hypothetical English-uniformity
7879/// pass renaming `"servicos"` → `"services"`) trips at build time.
7880///
7881/// [ch]: caixa_helm
7882/// [cf]: caixa_flux
7883pub const LAYOUT_DIR_SERVICOS: &str = "servicos";
7884
7885/// Canonical `wasm.pleme.io/v1alpha1/ComputeUnit` CRD `spec.module`
7886/// per-CR wasm-module-reference sub-block key — the top-level `spec.*`
7887/// child every rendered `ComputeUnit` YAML carries to name the wasm
7888/// component (`module.source: oci://...` for OCI-hosted binaries,
7889/// `module.source: file://...` for locally-mounted wasm bundles) the
7890/// M2.5 wasm-engine instantiator loads at Servico bring-up. The single
7891/// source of truth every downstream consumer that reads or emits the
7892/// per-CR module sub-block reaches for:
7893///
7894///   - [`caixa_flux::programs_yaml_entry`] splices the ComputeUnit
7895///     YAML's `spec.module` verbatim through into the emitted
7896///     `programs[]` entry (the `lareira-fleet-programs` library chart's
7897///     per-entry module-source axis, populated from the ComputeUnit's
7898///     `spec.module` per the docstring on `programs_yaml_entry` above);
7899///   - [`caixa_helm::build_values_yaml`] threads the same
7900///     `spec.module` sub-block into the rendered `values.yaml`'s
7901///     [`DEFAULT_LIBRARY_NAME`]-wrapped block so the `pleme-computeunit`
7902///     library chart's per-Servico module axis binds to the exact
7903///     source the caixa.lisp's `:servicos` fixture pins;
7904///   - every test-fixture navigator in both crates that reaches into
7905///     the rendered `programs[]` entry / `values.yaml` block by the
7906///     module sub-block key to pin the per-Servico module-source axis
7907///     round-trip (six sites across [`caixa_flux`][cf]'s per-entry
7908///     module + module.source drift-detection sweep + [`caixa_helm`][ch]'s
7909///     per-values module drift-detection sweep) resolves the same
7910///     `&'static str` when parsing back the rendered document;
7911///   - every future per-Servico renderer the absorption-roadmap
7912///     acknowledges (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
7913///     materializer's per-`:membros` module-source resolver, a future
7914///     per-cluster ComputeUnit-CR admission webhook keying off the same
7915///     accepted sub-block set, the future caixa-otel collector-pipeline
7916///     emitter's per-Servico module-scrape reference).
7917///
7918/// Until this lift landed the byte `"module"` lived as six verbatim
7919/// inline literals across [`caixa_flux`][cf] and [`caixa_helm`][ch]'s
7920/// test-fixture navigators (four sites in caixa-flux —
7921/// `programs_yaml_entry_round_trips`'s `entry.get("module")` pair +
7922/// `upsert_helmrelease_replaces_existing`'s `.get("module")` +
7923/// `upsert_into_programs_yaml`'s `.get("module")` — and two sites in
7924/// caixa-helm — `values_yaml_wraps_under_pleme_computeunit_key`'s
7925/// `cu_block.get("module")` + `values_yaml_wrap_key_follows_library_name_override`'s
7926/// peer navigator on the library-name-override axis). A future
7927/// ComputeUnit CRD schema-key rebrand on the per-CR module-reference
7928/// axis (the substrate moving the wasm-component reference to
7929/// `binary:` for parity with OCI OpenContainer Image nomenclature, to
7930/// `component:` for parity with WIT Component Model wire terminology,
7931/// to `spec.wasm.source` for schema-clarity once the ComputeUnit
7932/// CRD grows sibling `spec.native.*` / `spec.container.*` runtime-
7933/// discriminators as the ABSORPTION-ROADMAP.md M4-M5 trajectory names)
7934/// without a coordinated edit across all six sites would silently
7935/// split the schema: the emitter would write under the drifted key
7936/// while every downstream test would still probe `module:` — the
7937/// `lareira-fleet-programs` library chart's per-entry module-source
7938/// axis would silently receive an empty reference, the workload would
7939/// silently come up with no wasm module bound (the M2.5 instantiator
7940/// falls back to the library chart's admission-time default of a
7941/// hello-world stub, or fails the bring-up at wasm-engine parse time
7942/// with a diagnostic far from the caixa.lisp source), and the failure
7943/// would surface as "the Servico's pods are running but they aren't
7944/// running our code" far from the rebrand commit's source. Lifting
7945/// the literal to one `&'static str` closes the drift footgun
7946/// structurally — every consumer reads the same memory, so any
7947/// future rebrand reaches every consumer by construction.
7948///
7949/// Same "the typed constant lives in one place" discipline the peer
7950/// [`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`]
7951/// lifts apply on the sibling caixa.lisp M2 typed-slot canonical-
7952/// camelCase-key surfaces — extends the discipline from the caixa-
7953/// source-side M2 typed-slot overlay-key triple onto the substrate-
7954/// side `wasm.pleme.io/v1alpha1/ComputeUnit` CRD per-`spec.*`
7955/// sub-block axis every rendered ComputeUnit YAML declares as its
7956/// top-level `(module, trigger, capabilities)` triple (the peer
7957/// [`COMPUTEUNIT_SPEC_KEY_TRIGGER`] +
7958/// [`COMPUTEUNIT_SPEC_KEY_CAPABILITIES`] siblings complete the
7959/// substrate-side ComputeUnit-CRD per-`spec.*` sub-block re-export
7960/// triple).
7961///
7962/// [cf]: ../../caixa_flux/index.html
7963/// [ch]: ../../caixa_helm/index.html
7964pub const COMPUTEUNIT_SPEC_KEY_MODULE: &str = "module";
7965
7966/// Canonical `wasm.pleme.io/v1alpha1/ComputeUnit` CRD `spec.trigger`
7967/// per-CR invocation-trigger sub-block key — the top-level `spec.*`
7968/// child every rendered `ComputeUnit` YAML carries to name how the
7969/// wasm component is invoked (`trigger.service.{port, paths}` for
7970/// HTTP-triggered Servicos, `trigger.subscription.{subject}` for the
7971/// future NATS-triggered Servicos the M4 `:contratos` typed-mesh
7972/// pubsub axis will emit). Peer of [`COMPUTEUNIT_SPEC_KEY_MODULE`] on
7973/// the same ComputeUnit CRD per-`spec.*` sub-block surface —
7974/// `COMPUTEUNIT_SPEC_KEY_MODULE` names the per-CR wasm-binary
7975/// reference axis, this constant names the per-CR invocation-shape
7976/// axis every downstream trigger consumer (the `pleme-computeunit`
7977/// library chart's per-Servico `trigger.service.port` /
7978/// `trigger.service.paths` / `trigger.service.breathability` values-
7979/// block routing, the future M4 pubsub-subscription binding, the
7980/// `caixa-mesh` `CiliumNetworkPolicy` L4-port fallback that reads the
7981/// destination Servico's per-`trigger.service.port` axis via a future
7982/// resolver round-trip) reaches for. Same lift trajectory as the
7983/// sibling [`COMPUTEUNIT_SPEC_KEY_MODULE`] axis — three verbatim
7984/// inline test-side literals (one caixa-flux drift-detection navigator
7985/// + two caixa-helm per-values drift-detection navigators, one under
7986/// the canonical wrap-key + one under the library-name-override wrap-
7987/// key) collapsed onto the same `&'static str` so any future rebrand
7988/// (the substrate moving the invocation-shape axis to `invoke:`,
7989/// `entry:`, or splitting into `trigger.http.*` / `trigger.pubsub.*`
7990/// runtime-discriminators as the M4 `:contratos` axis grows) reaches
7991/// every consumer by construction. See [`COMPUTEUNIT_SPEC_KEY_MODULE`]
7992/// for the full lift rationale.
7993pub const COMPUTEUNIT_SPEC_KEY_TRIGGER: &str = "trigger";
7994
7995/// Canonical `wasm.pleme.io/v1alpha1/ComputeUnit` CRD
7996/// `spec.capabilities` per-CR WASI-capability-list sub-block key — the
7997/// top-level `spec.*` child every rendered `ComputeUnit` YAML carries
7998/// to declare the wasm-component-capability tokens the M2.5 wasm-engine
7999/// instantiator binds at Servico bring-up (`http-in:0.0.0.0:8080` for
8000/// the HTTP incoming-handler, `env` for read-only environment access,
8001/// `sock-*` for TCP outbound, and the sibling WASI-preview-2 preview-
8002/// interfaces per the WIT Component Model). Peer of
8003/// [`COMPUTEUNIT_SPEC_KEY_MODULE`] and [`COMPUTEUNIT_SPEC_KEY_TRIGGER`]
8004/// on the same ComputeUnit CRD per-`spec.*` sub-block surface —
8005/// completes the substrate-side ComputeUnit-CRD per-`spec.*` sub-block
8006/// re-export triple every rendered ComputeUnit YAML declares as its
8007/// top-level `(module, trigger, capabilities)` axis. Same lift
8008/// trajectory as the sibling [`COMPUTEUNIT_SPEC_KEY_MODULE`] axis —
8009/// three verbatim inline test-side literals (one caixa-flux drift-
8010/// detection navigator + two caixa-helm per-values drift-detection
8011/// navigators, one under the canonical wrap-key + one under the
8012/// library-name-override wrap-key) collapsed onto the same
8013/// `&'static str` so any future rebrand (the substrate moving the
8014/// capability-list axis to `caps:` for terse-schema parity with the
8015/// WASI-preview-2 upstream naming, splitting into
8016/// `capabilities.wasi.*` / `capabilities.pleme.*` runtime-vs-substrate
8017/// discriminators, or the M4 WIT Component Model materializer moving
8018/// to a typed `imports:` / `exports:` split) reaches every consumer by
8019/// construction. See [`COMPUTEUNIT_SPEC_KEY_MODULE`] for the full lift
8020/// rationale.
8021pub const COMPUTEUNIT_SPEC_KEY_CAPABILITIES: &str = "capabilities";
8022
8023/// Canonical `wasm.pleme.io/v1alpha1/ComputeUnit` CRD
8024/// `spec.module.source` per-CR wasm-component-reference leaf-scalar
8025/// sub-block key — the nested `spec.module.*` child every rendered
8026/// `ComputeUnit` YAML carries to name the exact wasm-component
8027/// artifact the M2.5 wasm-engine instantiator loads at Servico
8028/// bring-up. Peer of the parent [`COMPUTEUNIT_SPEC_KEY_MODULE`] on the
8029/// same ComputeUnit CRD per-`spec.module.*` sub-block surface —
8030/// `COMPUTEUNIT_SPEC_KEY_MODULE` names the top-level per-CR module-
8031/// reference block; this constant names the block's leaf reference-
8032/// value axis. Every rendered `programs[]` entry the
8033/// `lareira-fleet-programs` library chart consumes carries the
8034/// `module.source: oci://ghcr.io/pleme-io/<caixa>:<versao>` (or
8035/// `module.source: file://...` for locally-mounted wasm bundles;
8036/// `module.source: github:<owner>/<repo>` for git-hosted sources) as
8037/// its per-Servico wasm-artifact reference; every `spec.module.source`
8038/// readback across the [`caixa_flux::programs_yaml_entry`] round-trip
8039/// pins + the [`caixa_flux::upsert_into_programs_yaml`] /
8040/// [`caixa_flux::upsert_into_helmrelease_programs`] cross-upsert
8041/// navigators resolves the same `&'static str`.
8042///
8043/// Until this lift landed the byte `"source"` lived as three verbatim
8044/// inline literals across [`caixa_flux`][cf]'s test-fixture navigators
8045/// (`programs_yaml_entry_round_trips`'s
8046/// `entry.get(COMPUTEUNIT_SPEC_KEY_MODULE).and_then(|m| m.get("source"))`
8047/// per-`module.source` present-check +
8048/// `upsert_into_programs_yaml`'s
8049/// `arr[0].get(COMPUTEUNIT_SPEC_KEY_MODULE).get("source")` cross-
8050/// upsert readback + `upsert_into_helmrelease_programs`'s peer
8051/// navigator on the `HelmRelease`-wrapped `spec.values.programs[]`
8052/// path). A future ComputeUnit-CRD schema rebrand on the per-`module`
8053/// leaf-scalar axis (the substrate moving the reference-value axis to
8054/// `ref:` for parity with the OCI Distribution Spec's per-manifest
8055/// content-reference nomenclature, to `uri:` for parity with the WIT
8056/// Component Model's per-import content-reference field, to
8057/// `module.oci.ref` / `module.file.path` / `module.git.rev` sibling-
8058/// discriminator split once the ComputeUnit CRD grows typed sub-block
8059/// discriminators as the ABSORPTION-ROADMAP.md M4-M5 trajectory names)
8060/// without a coordinated three-site edit would silently split the
8061/// schema: the emitter would write under the drifted leaf-key while
8062/// every downstream navigator would still probe `source:` — the
8063/// `lareira-fleet-programs` library chart's per-entry module-source
8064/// axis would silently receive an empty reference, the workload would
8065/// silently come up with no wasm module bound (the M2.5 instantiator
8066/// falls back to the library chart's admission-time hello-world stub,
8067/// or fails the bring-up at wasm-engine parse time with a diagnostic
8068/// far from the caixa.lisp source), and the failure would surface as
8069/// "the Servico's pods are running but they aren't running our code"
8070/// far from the rebrand commit's source. Lifting the literal to one
8071/// `&'static str` closes the drift footgun structurally — every
8072/// consumer reads the same memory, so any future rebrand reaches every
8073/// consumer by construction.
8074///
8075/// Same "the typed constant lives in one place" discipline the peer
8076/// [`COMPUTEUNIT_SPEC_KEY_MODULE`] / [`COMPUTEUNIT_SPEC_KEY_TRIGGER`] /
8077/// [`COMPUTEUNIT_SPEC_KEY_CAPABILITIES`] lifts apply on the sibling
8078/// substrate-side ComputeUnit-CRD per-`spec.*` sub-block axis —
8079/// extends the discipline one level deeper from the top-level `spec.*`
8080/// container-axis surface onto the nested `spec.module.*` leaf-scalar-
8081/// axis every rendered ComputeUnit YAML declares under its per-CR
8082/// module-reference block.
8083///
8084/// [cf]: ../../caixa_flux/index.html
8085pub const COMPUTEUNIT_MODULE_KEY_SOURCE: &str = "source";
8086
8087/// Canonical YAML key for the M3 `:placement` slot's overlay on a
8088/// rendered programs.yaml entry. The lareira-fleet-programs aggregator
8089/// (and the future `app-operator` per-Aplicacao reconciler) both key
8090/// off this exact spelling to filter entries by `placement.clusters`
8091/// for cross-cluster fanout (MESH-COMPOSITION §III.4) and to dispatch
8092/// on `placement.estrategia` for distributed-app takeover semantics
8093/// (§II.1, §V cross-cluster federation). Lifted as a const alongside
8094/// the M2 keys so the Aplicacao-side renderer
8095/// ([`crate::aplicacao::Placement`] → caixa-mesh
8096/// `programs_for_aplicacao`) and every consumer (the M4 cluster-fanout
8097/// renderer, the future `mesh.pleme.io/v1alpha1/Aplicacao` CR
8098/// materializer, the `app-operator`'s placement-strategy dispatcher)
8099/// spell the same key exactly the same way — drift here = a
8100/// programs.yaml entry whose placement is silently dropped at the
8101/// aggregator's filter step (visible only as "the workload doesn't
8102/// land where the typed slot said it should").
8103pub const M3_KEY_PLACEMENT: &str = "placement";
8104
8105/// Canonical author-facing kebab-case `(defcaixa … :membros (…))`
8106/// top-level mesh slot label the M3 Aplicacao's constituent-Servico set
8107/// surfaces under. Peer of the four sibling M3 top-level mesh-slot
8108/// labels ([`M3_AUTHOR_KEY_CONTRATOS`], [`M3_AUTHOR_KEY_POLITICAS`],
8109/// [`M3_AUTHOR_KEY_PLACEMENT`], [`M3_AUTHOR_KEY_ENTRADA`]) on the
8110/// dual-axis pair every M3 top-level mesh slot carries: the
8111/// author-facing kebab-case `[M3_AUTHOR_KEY_*]` const names the label
8112/// the [`crate::Caixa::declared_mesh_slots`] tagger threads through as
8113/// one of the `&'static str` entries in the canonical-declaration-order
8114/// slot list the kind-coherence gate
8115/// ([`crate::LayoutError::MeshSlotsOnNonAplicacao`]) joins into the
8116/// space-separated `slots:` diagnostic naming which of the five mesh
8117/// slots the offending caixa declared on a non-Aplicacao kind. Peer of
8118/// the [`M3_KEY_PLACEMENT`] renderer-side wire-key const declared
8119/// immediately above on the sole M3 mesh slot the renderer surfaces as
8120/// a per-entry overlay-container key (`:membros` / `:contratos` /
8121/// `:politicas` / `:entrada` render as per-arm derived artifacts —
8122/// programs.yaml fan-out, CiliumNetworkPolicies, per-edge overlays,
8123/// Gateway/HTTPRoute — not as a single overlay-container key).
8124///
8125/// Until this lift landed the five kebab-case labels sat once each in
8126/// [`crate::Caixa::declared_mesh_slots`] as five-arm inline
8127/// `":membros"` / `":contratos"` / `":politicas"` / `":placement"` /
8128/// `":entrada"` byte-strings the tagger pushed onto its return `Vec`,
8129/// plus three test-side probe literals across `layout.rs` and
8130/// `manifest.rs::tests` — with no compile-time link between the
8131/// tagger's arms and the tests' expected values. A future rebrand
8132/// (a hypothetical `:membros` → `:members` matching English-uniformity
8133/// as the substrate's per-slot vocabulary stabilizes, `:contratos` →
8134/// `:contracts` matching the same, `:politicas` → `:policies`
8135/// matching the same, `:placement` → `:distribution` matching
8136/// MESH-COMPOSITION §II.1 vocabulary, `:entrada` → `:ingress` matching
8137/// K8s Gateway API's ingress-side vocabulary, or a per-consumer
8138/// disambiguation as the `defcaixa` macro stabilizes) would silently
8139/// desynchronize the production
8140/// [`crate::Caixa::declared_mesh_slots`] tagger from the tests until a
8141/// downstream consumer surfaced the drift at build time as a
8142/// matches-arm miss far from the rename's commit. This lift closes
8143/// that gap by routing both halves (production tagger + tests) through
8144/// five peer consts declared adjacent to the renderer-side
8145/// [`M3_KEY_PLACEMENT`] peer, so the "one canonical declaration per
8146/// arm, next to the axis" discipline the peer
8147/// [`M2_AUTHOR_KEY_LIMITS`] / [`M2_AUTHOR_KEY_BEHAVIOR`] /
8148/// [`M2_AUTHOR_KEY_UPGRADE_FROM`] top-level M2 slot consts
8149/// (f49c8b0) established for the sibling per-Servico M2 slot axis
8150/// extends onto the M3 top-level mesh slot axis so both altitudes
8151/// of the typed-slot algebra (per-Servico M2 + per-Aplicacao M3)
8152/// route through peer author-label consts.
8153pub const M3_AUTHOR_KEY_MEMBROS: &str = ":membros";
8154
8155/// Canonical author-facing kebab-case `(defcaixa … :contratos (…))`
8156/// top-level mesh slot label the M3 Aplicacao's WIT-typed inter-Servico
8157/// edge set surfaces under. Peer of [`M3_AUTHOR_KEY_MEMBROS`] on the
8158/// sibling M3 top-level mesh-slot dual axis; see
8159/// [`M3_AUTHOR_KEY_MEMBROS`] for the full lift rationale.
8160pub const M3_AUTHOR_KEY_CONTRATOS: &str = ":contratos";
8161
8162/// Canonical author-facing kebab-case `(defcaixa … :politicas (…))`
8163/// top-level mesh slot label the M3 Aplicacao's mesh-level policy
8164/// overlay ([`crate::aplicacao::MeshPolicy`]: `:timeout`, `:retries`,
8165/// `:circuit-breaker`, `:mtls-required`, `:rate-limit`) surfaces under.
8166/// Peer of [`M3_AUTHOR_KEY_MEMBROS`] on the sibling M3 top-level
8167/// mesh-slot dual axis; see [`M3_AUTHOR_KEY_MEMBROS`] for the full lift
8168/// rationale.
8169pub const M3_AUTHOR_KEY_POLITICAS: &str = ":politicas";
8170
8171/// Canonical author-facing kebab-case `(defcaixa … :placement (…))`
8172/// top-level mesh slot label the M3 Aplicacao's cross-cluster
8173/// distribution strategy ([`crate::aplicacao::Placement`]:
8174/// `:estrategia` + `:clusters` + `:shard-key` / `:affinity`) surfaces
8175/// under. Peer of [`M3_AUTHOR_KEY_MEMBROS`] on the sibling M3
8176/// top-level mesh-slot dual axis; see [`M3_AUTHOR_KEY_MEMBROS`] for
8177/// the full lift rationale. Byte-identical to the peer
8178/// [`M3_KEY_PLACEMENT`] renderer-side wire key modulo the leading `:`
8179/// — the two consts split on the axis every M3 top-level slot carries
8180/// (author-facing kebab-case label vs. renderer-side camelCase overlay
8181/// key), the same split the [`M2_AUTHOR_KEY_LIMITS`] / [`M2_KEY_LIMITS`]
8182/// peer pair established on the sibling M2 axis.
8183pub const M3_AUTHOR_KEY_PLACEMENT: &str = ":placement";
8184
8185/// Canonical author-facing kebab-case `(defcaixa … :entrada (…))`
8186/// top-level mesh slot label the M3 Aplicacao's external-ingress
8187/// gateway surface ([`crate::aplicacao::Entrada`]: `:host`, `:para`,
8188/// `:paths`, `:port`) surfaces under. Peer of [`M3_AUTHOR_KEY_MEMBROS`]
8189/// on the sibling M3 top-level mesh-slot dual axis; see
8190/// [`M3_AUTHOR_KEY_MEMBROS`] for the full lift rationale.
8191pub const M3_AUTHOR_KEY_ENTRADA: &str = ":entrada";
8192
8193/// Canonical author-facing kebab-case `(:de "<caixa>")` per-`:contratos`
8194/// entry source-endpoint sub-slot label the M3 Aplicacao's WIT-typed
8195/// inter-Servico edge set surfaces under. Names the "edge tail" —
8196/// which member `:contratos` entry `n` originates from — per
8197/// MESH-COMPOSITION §IV table row "`:contratos` | typed inter-Servico
8198/// edges | each :de + :para must be in :membros; :wit must reference a
8199/// registered WIT world".
8200///
8201/// Peer of [`M3_AUTHOR_KEY_CONTRATOS`] on the `:contratos` sub-slot
8202/// author-facing-label dual axis: the top-level [`M3_AUTHOR_KEY_CONTRATOS`]
8203/// const (882f498) names the M3 slot itself, the two
8204/// `CONTRATO_AUTHOR_KEY_{DE,PARA}` consts name the per-entry endpoint
8205/// axes the parser reads (`(:de "cart" :para "catalog" …)`).
8206///
8207/// Until this lift landed the two kebab-case labels sat once each in
8208/// [`crate::aplicacao::AplicacaoSpec::validate`]'s per-`:contratos`
8209/// entry endpoint-shape gate as two two-arm inline `":de"` / `":para"`
8210/// byte-strings passed as the `slot: &'static str` argument to
8211/// [`validate_contrato_caixa`], plus a family of test-side probe
8212/// literals asserting the [`crate::aplicacao::AplicacaoError::ContratoCaixaEmpty`]
8213/// / [`crate::aplicacao::AplicacaoError::ContratoCaixaInvalid`]
8214/// diagnostic's `slot:` field carries the expected per-arm value
8215/// verbatim — with no compile-time link between the validator's arms
8216/// and the tests' expected values. A future rebrand (a hypothetical
8217/// `:de` → `:from` for English uniformity matching the OTP `appup`
8218/// `M2_UPGRADE_FROM_KEY_FROM` (36ffe65) sibling, `:para` → `:to`
8219/// matching the same, `:de`/`:para` → `:source`/`:target` matching
8220/// the WIT world's `import`/`export` half-vocabulary, or a per-consumer
8221/// disambiguation as the `defcaixa` macro stabilizes) would silently
8222/// desynchronize the production per-entry endpoint-shape gate from the
8223/// tests until a downstream consumer surfaced the drift at build time
8224/// as a matches-arm miss far from the rename's commit. This lift closes
8225/// that gap by routing both halves (production endpoint-shape gate +
8226/// tests) through two peer consts declared adjacent to the
8227/// [`M3_AUTHOR_KEY_CONTRATOS`] parent-slot label, so the "one
8228/// canonical declaration per arm, next to the axis" discipline the
8229/// peer [`M2_AUTHOR_KEY_LIMITS`] / [`M2_AUTHOR_KEY_BEHAVIOR`] /
8230/// [`M2_AUTHOR_KEY_UPGRADE_FROM`] (f49c8b0), [`M3_AUTHOR_KEY_MEMBROS`]
8231/// / [`M3_AUTHOR_KEY_CONTRATOS`] / [`M3_AUTHOR_KEY_POLITICAS`] /
8232/// [`M3_AUTHOR_KEY_PLACEMENT`] / [`M3_AUTHOR_KEY_ENTRADA`] (882f498),
8233/// and [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] etc. (be40492) top-level
8234/// slot consts established for the sibling M2 / M3 / Supervisor
8235/// top-level slot axes extends onto the `:contratos` sub-slot
8236/// endpoint axis.
8237pub const CONTRATO_AUTHOR_KEY_DE: &str = ":de";
8238
8239/// Canonical author-facing kebab-case `(:para "<caixa>")` per-`:contratos`
8240/// entry target-endpoint sub-slot label the M3 Aplicacao's WIT-typed
8241/// inter-Servico edge set surfaces under. Names the "edge head" —
8242/// which member `:contratos` entry `n` terminates at — per
8243/// MESH-COMPOSITION §IV table row "`:contratos` | typed inter-Servico
8244/// edges | each :de + :para must be in :membros". Peer of
8245/// [`CONTRATO_AUTHOR_KEY_DE`] on the sibling `:contratos` per-entry
8246/// endpoint-shape axis; see [`CONTRATO_AUTHOR_KEY_DE`] for the full
8247/// lift rationale.
8248pub const CONTRATO_AUTHOR_KEY_PARA: &str = ":para";
8249
8250/// Canonical author-facing kebab-case `(defcaixa … :estrategia <s>)`
8251/// top-level supervisor-tree slot label the OTP `:kind Supervisor`
8252/// caixa's [`crate::supervisor::RestartStrategy`] discriminator surfaces
8253/// under. Peer of [`M2_AUTHOR_KEY_LIMITS`] /
8254/// [`M3_AUTHOR_KEY_MEMBROS`] on the third kind-scoped
8255/// typed-slot-family axis: the M2 `M2_AUTHOR_KEY_*` consts (f49c8b0)
8256/// name the Servico-runtime slots, the M3 `M3_AUTHOR_KEY_*` consts
8257/// (882f498) name the Aplicacao mesh slots, and these
8258/// `SUPERVISOR_AUTHOR_KEY_*` consts close the last remaining kind ↔
8259/// slot-family axis — the Supervisor supervision-tree slots
8260/// (`:estrategia`, `:max-restarts`, `:restart-window`, `:children`) that
8261/// [`crate::Caixa::declared_supervisor_slots`] tags for the sibling
8262/// [`crate::LayoutError::SupervisorSlotsOnNonSupervisor`]
8263/// kind-coherence gate.
8264///
8265/// Until this lift landed the four kebab-case labels sat once each in
8266/// [`crate::Caixa::declared_supervisor_slots`] as four-arm inline
8267/// `":estrategia"` / `":max-restarts"` / `":restart-window"` /
8268/// `":children"` byte-strings the tagger pushed onto its return `Vec`,
8269/// plus a handful of test-side probe literals asserting the diagnostic's
8270/// `slots:` field carries the expected per-arm value verbatim — with no
8271/// compile-time link between the tagger's arms and the tests' expected
8272/// values. A future rebrand (a hypothetical `:estrategia` →
8273/// `:strategy` for English uniformity, `:max-restarts` →
8274/// `:max-intensity` matching Erlang/OTP's `MaxIntensity` terminology
8275/// verbatim, `:restart-window` → `:period` matching OTP's `Period` name,
8276/// `:children` → `:workers` matching the Elixir `Supervisor.child_spec`
8277/// idiom, or a per-consumer disambiguation as the `defcaixa` macro
8278/// stabilizes) would silently desynchronize the production
8279/// [`crate::Caixa::declared_supervisor_slots`] tagger from the tests
8280/// until a downstream consumer surfaced the drift at build time as a
8281/// matches-arm miss far from the rename's commit. This lift closes that
8282/// gap by routing both halves (production tagger + tests) through four
8283/// peer consts declared adjacent to the peer M2 / M3 top-level
8284/// author-key consts, so the "one canonical declaration per arm, next
8285/// to the axis" discipline the peer [`M2_AUTHOR_KEY_LIMITS`] /
8286/// [`M2_AUTHOR_KEY_BEHAVIOR`] / [`M2_AUTHOR_KEY_UPGRADE_FROM`] top-level
8287/// M2 slot consts (f49c8b0) and [`M3_AUTHOR_KEY_MEMBROS`] /
8288/// [`M3_AUTHOR_KEY_CONTRATOS`] / [`M3_AUTHOR_KEY_POLITICAS`] /
8289/// [`M3_AUTHOR_KEY_PLACEMENT`] / [`M3_AUTHOR_KEY_ENTRADA`] top-level
8290/// M3 slot consts (882f498) established for the sibling
8291/// per-Servico / per-Aplicacao top-level slot axes extends onto the
8292/// per-Supervisor supervision-tree slot axis, closing the last of the
8293/// three kind-scoped typed-slot-family author-facing-label axes.
8294///
8295/// Same "one canonical byte-string per typed axis" discipline every
8296/// peer M2 / M3 renderer-wire-key axis carries ([`M2_KEY_LIMITS`] /
8297/// [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`],
8298/// [`M2_LIMITS_KEY_MEMORY`] / [`M2_LIMITS_KEY_FUEL`] /
8299/// [`M2_LIMITS_KEY_WALL_CLOCK`] / [`M2_LIMITS_KEY_CPU`] (d8b8b4f),
8300/// [`M2_BEHAVIOR_KEY_ON_INIT`] etc. (21fe462),
8301/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
8302/// (36ffe65), [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.).
8303pub const SUPERVISOR_AUTHOR_KEY_ESTRATEGIA: &str = ":estrategia";
8304/// Canonical author-facing kebab-case `(defcaixa … :max-restarts <n>)`
8305/// top-level supervisor-tree slot label the OTP `:kind Supervisor`
8306/// caixa's `MaxIntensity` restart-budget counter surfaces under. Peer of
8307/// [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] on the sibling supervision-tree
8308/// slot axis; see [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] for the full lift
8309/// rationale.
8310pub const SUPERVISOR_AUTHOR_KEY_MAX_RESTARTS: &str = ":max-restarts";
8311/// Canonical author-facing kebab-case
8312/// `(defcaixa … :restart-window "<duration>")` top-level supervisor-tree
8313/// slot label the OTP `:kind Supervisor` caixa's `Period` rolling-window
8314/// counter surfaces under. Peer of [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`]
8315/// on the sibling supervision-tree slot axis; see
8316/// [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] for the full lift rationale.
8317pub const SUPERVISOR_AUTHOR_KEY_RESTART_WINDOW: &str = ":restart-window";
8318/// Canonical author-facing kebab-case `(defcaixa … :children (…))`
8319/// top-level supervisor-tree slot label the OTP `:kind Supervisor`
8320/// caixa's static child-spec list ([`crate::supervisor::ChildSpec`])
8321/// surfaces under. Peer of [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] on the
8322/// sibling supervision-tree slot axis; see
8323/// [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] for the full lift rationale.
8324pub const SUPERVISOR_AUTHOR_KEY_CHILDREN: &str = ":children";
8325
8326/// Canonical author-facing kebab-case `(defcaixa … :deps ((…)))` top-
8327/// level dep-list slot label the two-list dependency-graph slot family
8328/// surfaces under. Peer of [`DEP_AUTHOR_KEY_DEPS_DEV`] on the two-list
8329/// dep-graph slot axis: `:deps` names the runtime-closure dep-list
8330/// (every `Cargo.toml [dependencies]` equivalent — reached by every
8331/// build the caixa participates in), the sibling `:deps-dev` names the
8332/// dev-only dep-list (every `Cargo.toml [dev-dependencies]` equivalent
8333/// — reached only by test / dev-shim builds).
8334///
8335/// Threaded verbatim as the `list: &'static str` field on both
8336/// [`crate::DepError::DuplicateNome`] (359fba5) and
8337/// [`crate::DepError::DepIsSelf`] so a `feira lint` diagnostic ("`:deps`
8338/// entry `caixa-teia` is duplicated" / "`:deps-dev` entry `dev-shim` is
8339/// a self-reference") self-locates the offending block in the author's
8340/// `caixa.lisp` without the linter re-deriving the list from context.
8341///
8342/// Until this lift landed the two kebab-case labels sat once each on
8343/// the [`crate::Caixa::validate_deps`] per-list duplicate walk (`list:
8344/// ":deps"` / `list: ":deps-dev"` in `manifest.rs`) and the paired
8345/// [`crate::dep::validate_no_self_dep`] per-list self-edge walk (`list:
8346/// ":deps"` / `list: ":deps-dev"` in `dep.rs`), plus a handful of
8347/// test-side probe literals asserting the `list:` field of a
8348/// `DepError::DuplicateNome` / `DepError::DepIsSelf` carries the
8349/// expected per-list value verbatim — with no compile-time link
8350/// between the two producers and the tests' expected values. A future
8351/// rebrand (a hypothetical `:deps` → `:dependencies` matching Cargo's
8352/// verbatim key, `:deps-dev` → `:dev-dependencies` matching the same,
8353/// `:deps` / `:deps-dev` → `:runtime-deps` / `:dev-deps` for
8354/// symmetry, or a per-consumer disambiguation as the `defcaixa` macro
8355/// stabilizes) would silently desynchronize the two producers from
8356/// each other and from the tests until a downstream consumer surfaced
8357/// the drift at build time as a matches-arm miss far from the
8358/// rename's commit. This lift closes that gap by routing all halves
8359/// (both production walkers + tests) through two peer consts declared
8360/// adjacent to the peer M2 / M3 / Supervisor top-level author-key
8361/// consts, so the "one canonical declaration per arm, next to the
8362/// axis" discipline the peer [`M2_AUTHOR_KEY_LIMITS`] /
8363/// [`M2_AUTHOR_KEY_BEHAVIOR`] / [`M2_AUTHOR_KEY_UPGRADE_FROM`]
8364/// (f49c8b0), [`M3_AUTHOR_KEY_MEMBROS`] / [`M3_AUTHOR_KEY_CONTRATOS`] /
8365/// [`M3_AUTHOR_KEY_POLITICAS`] / [`M3_AUTHOR_KEY_PLACEMENT`] /
8366/// [`M3_AUTHOR_KEY_ENTRADA`] (882f498), [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`]
8367/// etc. (be40492), and [`CONTRATO_AUTHOR_KEY_DE`] /
8368/// [`CONTRATO_AUTHOR_KEY_PARA`] (f50c875) top-level slot / per-entry
8369/// endpoint consts established for the sibling M2 / M3 / Supervisor
8370/// slot axes extends onto the two-list dep-graph slot axis.
8371///
8372/// Byte-identical to the peer [`CAIXA_KEY_DEPS`] renderer-side wire-key
8373/// serde-key axis modulo the leading `:` — the two consts split on the
8374/// axis every dep-graph slot carries (author-facing kebab-case label vs.
8375/// renderer-side wire key). Same "one canonical byte-string per typed
8376/// axis" discipline every peer M2 / M3 renderer-wire-key axis carries.
8377pub const DEP_AUTHOR_KEY_DEPS: &str = ":deps";
8378
8379/// Canonical author-facing kebab-case `(defcaixa … :deps-dev ((…)))`
8380/// top-level dep-list slot label the dev-only two-list dependency-graph
8381/// slot family surfaces under. Peer of [`DEP_AUTHOR_KEY_DEPS`] on the
8382/// two-list dep-graph slot axis; see [`DEP_AUTHOR_KEY_DEPS`] for the
8383/// full lift rationale.
8384pub const DEP_AUTHOR_KEY_DEPS_DEV: &str = ":deps-dev";
8385
8386/// Canonical camelCase JSON/YAML top-level key for
8387/// [`crate::supervisor::SupervisorSpec`]'s `estrategia` restart-strategy
8388/// discriminator — the exact byte-sequence the type's
8389/// `#[serde(rename_all = "camelCase")]` derive emits, and the scalar every
8390/// downstream JSON/YAML consumer that reaches into a serialized
8391/// `SupervisorSpec` (via `Value::get(...)`) must probe on.
8392///
8393/// The scalar is derived from the Rust field name `estrategia` by the
8394/// `rename_all = "camelCase"` derive; `estrategia` has no `_`, so the
8395/// serde transform is a no-op on this axis and the emitted key equals the
8396/// source-side field name byte-for-byte. Lifting the byte to one
8397/// `&'static str` closes the drift footgun structurally: a future
8398/// refactor renaming the Rust field OR retaining the field name while
8399/// adding a `#[serde(rename = "…")]` override would silently emit a
8400/// `SupervisorSpec` whose restart-strategy discriminator lands under one
8401/// key while every downstream consumer still probes another — the
8402/// future wasm-operator's supervisor reconcile posture, the M4
8403/// `caixa.pleme.io/v1alpha1/Supervisor` CR materializer's admission
8404/// webhook, the future `feira lint` supervisor-tree cross-check. The
8405/// identity pin (`supervisor_spec_serde_keys_match_lifted_supervisor_key_consts`
8406/// on the source-side type) catches drift at caixa-core build time
8407/// rather than at the reconciler's dispatch step, far from the rebrand
8408/// commit's source.
8409///
8410/// Peer of the sibling author-facing
8411/// [`SUPERVISOR_AUTHOR_KEY_ESTRATEGIA`] (`":estrategia"`) on the same
8412/// per-Supervisor supervision-tree slot axis — that constant names the
8413/// kebab-case `(defcaixa … :estrategia …)` author surface's top-level
8414/// slot label, this one names the camelCase JSON/YAML sub-key the
8415/// serialized `SupervisorSpec` carries the same axis under. Byte-distinct
8416/// from (though semantically related to) the peer
8417/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] (also `"estrategia"`) on the M3
8418/// [`crate::aplicacao::Placement`] axis — that axis carries
8419/// [`crate::aplicacao::PlacementStrategy`] cross-cluster distribution
8420/// semantics, this axis carries [`crate::supervisor::RestartStrategy`]
8421/// OTP supervisor semantics; splitting the two lets each schema's
8422/// future rebrand land independently on the same
8423/// "byte-identical-but-semantically-distinct" discipline the peer
8424/// [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`] split established.
8425///
8426/// Same "one canonical byte-string per typed serialized-key axis"
8427/// discipline every peer camelCase serde-key lift carries
8428/// ([`M2_LIMITS_KEY_MEMORY`] / [`M2_LIMITS_KEY_FUEL`] /
8429/// [`M2_LIMITS_KEY_WALL_CLOCK`] / [`M2_LIMITS_KEY_CPU`] (d8b8b4f),
8430/// [`M2_BEHAVIOR_KEY_ON_INIT`] etc. (21fe462),
8431/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
8432/// (36ffe65), [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.) — extended here to
8433/// close the last of the four top-level typed-struct
8434/// `#[serde(rename_all = "camelCase")]` axes lacking a lifted peer.
8435pub const SUPERVISOR_KEY_ESTRATEGIA: &str = "estrategia";
8436
8437/// Canonical camelCase JSON/YAML top-level key for
8438/// [`crate::supervisor::SupervisorSpec`]'s `max_restarts` axis. Peer of
8439/// [`SUPERVISOR_KEY_ESTRATEGIA`] on the same sibling
8440/// supervision-tree serialized-key axis; see [`SUPERVISOR_KEY_ESTRATEGIA`]
8441/// for the full lift rationale. The Rust field is `snake_case`
8442/// `max_restarts`; `#[serde(rename_all = "camelCase")]` maps it to the
8443/// camelCase JSON key `"maxRestarts"` this constant pins.
8444pub const SUPERVISOR_KEY_MAX_RESTARTS: &str = "maxRestarts";
8445
8446/// Canonical camelCase JSON/YAML top-level key for
8447/// [`crate::supervisor::SupervisorSpec`]'s `restart_window` axis. Peer of
8448/// [`SUPERVISOR_KEY_ESTRATEGIA`] on the same sibling
8449/// supervision-tree serialized-key axis; see [`SUPERVISOR_KEY_ESTRATEGIA`]
8450/// for the full lift rationale. The Rust field is `snake_case`
8451/// `restart_window`; `#[serde(rename_all = "camelCase")]` maps it to the
8452/// camelCase JSON key `"restartWindow"` this constant pins.
8453pub const SUPERVISOR_KEY_RESTART_WINDOW: &str = "restartWindow";
8454
8455/// Canonical camelCase JSON/YAML top-level key for
8456/// [`crate::supervisor::SupervisorSpec`]'s `children` axis. Peer of
8457/// [`SUPERVISOR_KEY_ESTRATEGIA`] on the same sibling
8458/// supervision-tree serialized-key axis; see [`SUPERVISOR_KEY_ESTRATEGIA`]
8459/// for the full lift rationale. The Rust field is lowercase `children`;
8460/// `#[serde(rename_all = "camelCase")]` is a no-op on this axis and the
8461/// emitted key equals the source-side field name byte-for-byte.
8462pub const SUPERVISOR_KEY_CHILDREN: &str = "children";
8463
8464/// Canonical camelCase JSON/YAML top-level key for the
8465/// [`crate::supervisor::ChildSpec`] struct's `caixa` per-entry-name-of-
8466/// the-child-caixa axis — the `caixa:` field the M2 Supervisor's
8467/// `#[serde(rename_all = "camelCase")]` derive on
8468/// [`crate::supervisor::ChildSpec`] emits at each entry of the
8469/// [`crate::supervisor::SupervisorSpec::children`] list, and the exact
8470/// scalar every downstream consumer reaching for the child caixa's
8471/// [`crate::Caixa::nome`] via `Value::get(...)` (the future wasm-operator's
8472/// per-supervisor-tree child resolver, the M4
8473/// `caixa.pleme.io/v1alpha1/Supervisor` CR materializer's admission
8474/// webhook per-child cross-check, the future `feira` supervisor-tree
8475/// walker's per-child name-lookup, the [`caixa_resolver`] per-child
8476/// git-clone step) must probe on.
8477///
8478/// The scalar is derived from the Rust field name `caixa` by the
8479/// `rename_all = "camelCase"` derive; `caixa` has no `_`, so the serde
8480/// transform is a no-op on this axis and the emitted key equals the
8481/// source-side field name byte-for-byte. Lifting the byte to one
8482/// `&'static str` closes the drift footgun structurally: a future
8483/// refactor renaming the Rust field OR retaining the field name while
8484/// adding a `#[serde(rename = "…")]` override would silently emit a
8485/// `ChildSpec` whose per-entry child-caixa discriminator lands under
8486/// one key while every downstream consumer still probes another. The
8487/// identity pin (`child_spec_serde_keys_match_lifted_supervisor_child_key_consts`
8488/// on the source-side type) catches drift at caixa-core build time
8489/// rather than at the reconciler's dispatch step, far from the rebrand
8490/// commit's source.
8491///
8492/// Peer of [`SUPERVISOR_CHILD_KEY_VERSAO`] / [`SUPERVISOR_CHILD_KEY_RESTART`]
8493/// on the same [`crate::supervisor::ChildSpec`] per-entry serialized-key
8494/// axis. Peer of the sibling [`SUPERVISOR_KEY_ESTRATEGIA`] /
8495/// [`SUPERVISOR_KEY_MAX_RESTARTS`] / [`SUPERVISOR_KEY_RESTART_WINDOW`] /
8496/// [`SUPERVISOR_KEY_CHILDREN`] tetrad (40cc4e5) on the enclosing
8497/// [`crate::supervisor::SupervisorSpec`] top-level serialized-key axis
8498/// — that lift pinned the four camelCase JSON keys the M2
8499/// supervision-tree top-level derive emits, this lift extends the same
8500/// discipline onto the sibling per-entry `ChildSpec` derive so the last
8501/// M2 typed-struct sub-block `#[serde(rename_all = "camelCase")]` axis
8502/// on the Supervisor surface without a lifted serde-key peer joins the
8503/// substrate's "one canonical byte-string per typed serialized-key axis"
8504/// discipline.
8505///
8506/// Byte-identical to (but semantically distinct from) the peer
8507/// [`MEMBRO_KEY_CAIXA`] (ce80ca0) on the sibling M3
8508/// [`crate::aplicacao::Membro`] per-`:membros` entry axis — both axes
8509/// carry per-entry caixa-name discriminators on typed list slots, but
8510/// splitting the two lets each schema's future rebrand land
8511/// independently at its canonical const definition without coupling
8512/// the M2 Supervisor per-child axis to the M3 Aplicacao per-member axis
8513/// (or vice versa) — same "byte-identical-but-semantically-distinct"
8514/// discipline the peer [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`]
8515/// split established.
8516///
8517/// Same "one canonical byte-string per typed serialized-key axis"
8518/// discipline every peer camelCase serde-key lift carries
8519/// ([`M2_LIMITS_KEY_MEMORY`] etc. (d8b8b4f), [`M2_BEHAVIOR_KEY_ON_INIT`]
8520/// etc. (21fe462), [`M2_UPGRADE_FROM_KEY_FROM`] /
8521/// [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`] (36ffe65),
8522/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc., [`SUPERVISOR_KEY_ESTRATEGIA`]
8523/// etc. (40cc4e5), [`MEMBRO_KEY_CAIXA`] / [`MEMBRO_KEY_VERSAO`]
8524/// (ce80ca0), [`CONTRATO_KEY_DE`] / [`CONTRATO_KEY_PARA`] /
8525/// [`CONTRATO_KEY_WIT`] (ca463a4), [`ENTRADA_KEY_HOST`] etc. (a3d6162),
8526/// [`POLITICAS_KEY_TIMEOUT`] etc. (b55cca7), [`CIRCUIT_BREAKER_KEY_MAX_FAILURES`]
8527/// / [`CIRCUIT_BREAKER_KEY_WINDOW`] (468e959)) — extended here to the
8528/// last M2 typed-struct sub-block `#[serde(rename_all = "camelCase")]`
8529/// axis on the Supervisor surface, the per-`:children` entry
8530/// [`crate::supervisor::ChildSpec`] derive.
8531pub const SUPERVISOR_CHILD_KEY_CAIXA: &str = "caixa";
8532
8533/// Canonical camelCase JSON/YAML top-level key for the
8534/// [`crate::supervisor::ChildSpec`] struct's `versao` per-entry-semver-
8535/// constraint-of-the-child axis. Peer of [`SUPERVISOR_CHILD_KEY_CAIXA`]
8536/// on the same [`crate::supervisor::ChildSpec`] per-entry serialized-key
8537/// axis; see [`SUPERVISOR_CHILD_KEY_CAIXA`] for the full lift rationale.
8538/// The Rust field is lowercase `versao`; `#[serde(rename_all = "camelCase")]`
8539/// is a no-op on this axis and the emitted key equals the source-side
8540/// field name byte-for-byte.
8541///
8542/// Byte-identical to (but semantically distinct from) the peer
8543/// [`MEMBRO_KEY_VERSAO`] (ce80ca0) on the sibling M3
8544/// [`crate::aplicacao::Membro`] per-`:membros` entry axis and the peer
8545/// [`FLEET_PROGRAMS_KEY_VERSAO`] on the `lareira-fleet-programs`
8546/// library-chart values-schema axis — same
8547/// "byte-identical-but-semantically-distinct" discipline the peer
8548/// [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`] /
8549/// [`MEMBRO_KEY_CAIXA`] / [`SUPERVISOR_CHILD_KEY_CAIXA`] splits
8550/// established: each schema's future rebrand lands independently at its
8551/// canonical const definition without coupling one axis to the others.
8552pub const SUPERVISOR_CHILD_KEY_VERSAO: &str = "versao";
8553
8554/// Canonical camelCase JSON/YAML top-level key for the
8555/// [`crate::supervisor::ChildSpec`] struct's `restart` per-entry
8556/// [`crate::supervisor::RestartPolicy`] discriminator axis. Peer of
8557/// [`SUPERVISOR_CHILD_KEY_CAIXA`] on the same
8558/// [`crate::supervisor::ChildSpec`] per-entry serialized-key axis; see
8559/// [`SUPERVISOR_CHILD_KEY_CAIXA`] for the full lift rationale. The Rust
8560/// field is lowercase `restart`; `#[serde(rename_all = "camelCase")]`
8561/// is a no-op on this axis and the emitted key equals the source-side
8562/// field name byte-for-byte.
8563pub const SUPERVISOR_CHILD_KEY_RESTART: &str = "restart";
8564
8565/// Canonical camelCase JSON/YAML top-level key for the
8566/// [`crate::aplicacao::Membro`] struct's `caixa` per-entry-name-of-the-
8567/// member-Servico axis — the `caixa:` field the M3 Aplicacao's
8568/// `#[serde(rename_all = "camelCase")]` derive on [`crate::aplicacao::Membro`]
8569/// emits at each `:membros` entry, and the exact scalar every downstream
8570/// `#[serde(rename_all = "camelCase")]` derive on [`crate::aplicacao::Membro`]
8571/// emits at each `:membros` entry, and the exact scalar every downstream
8572/// consumer reaching for the member's [`crate::Caixa::nome`] via
8573/// `Value::get(...)` (the future wasm-operator's per-`:membros` resolver,
8574/// the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission
8575/// webhook, the `feira app graph` verb's per-member name-lookup, the
8576/// [`caixa_resolver`] per-`:membros` git-clone step) must probe on.
8577///
8578/// The scalar is derived from the Rust field name `caixa` by the
8579/// `rename_all = "camelCase"` derive; `caixa` has no `_`, so the
8580/// serde transform is a no-op on this axis and the emitted key equals
8581/// the source-side field name byte-for-byte. Lifting the byte to one
8582/// `&'static str` closes the drift footgun structurally: a future
8583/// refactor renaming the Rust field OR retaining the field name while
8584/// adding a `#[serde(rename = "…")]` override would silently emit a
8585/// `Membro` whose per-entry name discriminator lands under one key while
8586/// every downstream consumer still probes another — the future wasm-
8587/// operator's per-`:membros` resolver, the M4 CR materializer's admission
8588/// webhook, the `feira app graph` verb's per-member name-lookup. The
8589/// identity pin (`membro_serde_keys_match_lifted_membro_key_consts` on
8590/// the source-side type) catches drift at caixa-core build time rather
8591/// than at the reconciler's dispatch step, far from the rebrand commit's
8592/// source.
8593///
8594/// Peer of [`MEMBRO_KEY_VERSAO`] on the same [`crate::aplicacao::Membro`]
8595/// per-entry serialized-key axis. Peer of the sibling
8596/// [`SUPERVISOR_KEY_ESTRATEGIA`] / [`SUPERVISOR_KEY_MAX_RESTARTS`] /
8597/// [`SUPERVISOR_KEY_RESTART_WINDOW`] / [`SUPERVISOR_KEY_CHILDREN`] tetrad
8598/// (40cc4e5) on the sibling `SupervisorSpec` top-level serialized-key
8599/// axis — that lift pinned the four camelCase JSON keys the M2
8600/// supervision-tree top-level derive emits, this lift extends the same
8601/// discipline onto the M3 Aplicacao's per-`:membros` entry derive.
8602///
8603/// Same "one canonical byte-string per typed serialized-key axis"
8604/// discipline every peer camelCase serde-key lift carries
8605/// ([`M2_LIMITS_KEY_MEMORY`] etc. (d8b8b4f), [`M2_BEHAVIOR_KEY_ON_INIT`]
8606/// etc. (21fe462), [`M2_UPGRADE_FROM_KEY_FROM`] /
8607/// [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`] (36ffe65),
8608/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc., [`SUPERVISOR_KEY_ESTRATEGIA`]
8609/// etc. (40cc4e5)) — extended here to the M3 [`crate::aplicacao::Membro`]
8610/// per-entry axis, the last top-level typed-struct
8611/// `#[serde(rename_all = "camelCase")]` axis on the M3 mesh-slot family
8612/// lacking a lifted peer.
8613pub const MEMBRO_KEY_CAIXA: &str = "caixa";
8614
8615/// Canonical camelCase JSON/YAML top-level key for the
8616/// [`crate::aplicacao::Membro`] struct's `versao` per-entry-semver-
8617/// constraint-of-the-member axis. Peer of [`MEMBRO_KEY_CAIXA`] on the
8618/// same [`crate::aplicacao::Membro`] per-entry serialized-key axis; see
8619/// [`MEMBRO_KEY_CAIXA`] for the full lift rationale. The Rust field is
8620/// lowercase `versao`; `#[serde(rename_all = "camelCase")]` is a no-op
8621/// on this axis and the emitted key equals the source-side field name
8622/// byte-for-byte.
8623///
8624/// Byte-identical to [`FLEET_PROGRAMS_KEY_VERSAO`] today — both resolve
8625/// to the same six-byte `"versao"` literal — but semantically distinct:
8626/// [`FLEET_PROGRAMS_KEY_VERSAO`] names the `lareira-fleet-programs`
8627/// library chart's per-entry version-constraint schema-axis (spelled
8628/// per the chart's `values.schema.json` — the same schema surface
8629/// [`caixa_mesh::programs_for_aplicacao`] transcribes each `:membros`
8630/// entry's version constraint into), while this constant names the
8631/// [`crate::aplicacao::Membro`] typed struct's derive-emitted `versao`
8632/// field key (spelled per the type's `#[serde(rename_all = "camelCase")]`
8633/// attribute — a separate schema contract on the upstream typed
8634/// manifest). Splitting the two lets each schema's future rebrand land
8635/// independently at its canonical const definition without coupling the
8636/// Membro typed-struct axis to the fleet-programs values-schema axis
8637/// (or vice versa) — same "byte-identical-but-semantically-distinct"
8638/// discipline the peer [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`]
8639/// split established on the sibling per-entry name-discriminator axis.
8640pub const MEMBRO_KEY_VERSAO: &str = "versao";
8641
8642/// Canonical camelCase JSON/YAML top-level key for the
8643/// [`crate::aplicacao::WitContract`] struct's `de` per-entry
8644/// source-endpoint-of-the-contract axis — the `de:` field the M3
8645/// Aplicacao's `#[serde(rename_all = "camelCase")]` derive on
8646/// [`crate::aplicacao::WitContract`] emits at each `:contratos` entry,
8647/// and the exact scalar every downstream consumer reaching for the
8648/// caller-Servico name via `Value::get(...)` (the future
8649/// wasm-operator's per-`:contratos` edge resolver, the M4
8650/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission
8651/// webhook per-edge cross-check, the `feira app graph` verb's per-edge
8652/// tail-label lookup, the future per-`:contratos` `CiliumNetworkPolicy`
8653/// emitter's per-edge `fromEndpoints` selector projection) must probe on.
8654///
8655/// The scalar is derived from the Rust field name `de` by the
8656/// `rename_all = "camelCase"` derive; `de` has no `_`, so the serde
8657/// transform is a no-op on this axis and the emitted key equals the
8658/// source-side field name byte-for-byte. Lifting the byte to one
8659/// `&'static str` closes the drift footgun structurally: a future
8660/// refactor renaming the Rust field OR retaining the field name while
8661/// adding a `#[serde(rename = "…")]` override would silently emit a
8662/// `WitContract` whose per-entry caller-Servico discriminator lands
8663/// under one key while every downstream consumer still probes another —
8664/// the future wasm-operator's per-`:contratos` edge resolver, the M4 CR
8665/// materializer's admission webhook per-edge cross-check, the
8666/// `feira app graph` verb's per-edge tail-label lookup. The identity pin
8667/// (`wit_contract_serde_keys_match_lifted_contrato_key_consts` on the
8668/// source-side type) catches drift at caixa-core build time rather than
8669/// at the reconciler's dispatch step, far from the rebrand commit's
8670/// source.
8671///
8672/// Peer of [`CONTRATO_KEY_PARA`] / [`CONTRATO_KEY_WIT`] on the same
8673/// [`crate::aplicacao::WitContract`] per-entry serialized-key axis. Peer
8674/// of the sibling [`MEMBRO_KEY_CAIXA`] / [`MEMBRO_KEY_VERSAO`] pair
8675/// (ce80ca0) on the sibling M3 [`crate::aplicacao::Membro`] per-entry
8676/// serialized-key axis — that lift pinned the two camelCase JSON keys
8677/// the M3 per-`:membros` derive emits, this lift extends the same
8678/// discipline onto the sibling M3 per-`:contratos` derive so the last
8679/// M3 mesh-slot atom top-level `#[serde(rename_all = "camelCase")]`
8680/// axis on the Aplicacao surface without a lifted peer joins the
8681/// substrate's "one canonical byte-string per typed serialized-key
8682/// axis" discipline.
8683///
8684/// Byte-identical to (but semantically distinct from) the sibling
8685/// author-facing kebab-case [`CONTRATO_AUTHOR_KEY_DE`] (f50c875) modulo
8686/// the leading `:` — the two consts split on the axis every M3 mesh-slot
8687/// atom carries (author-facing kebab-case label vs. renderer-side
8688/// camelCase overlay key), the same split the [`M2_AUTHOR_KEY_LIMITS`] /
8689/// [`M2_KEY_LIMITS`] peer pair established on the sibling M2 axis and
8690/// the [`M3_AUTHOR_KEY_PLACEMENT`] / [`M3_KEY_PLACEMENT`] peer pair
8691/// established on the sibling M3 top-level slot axis.
8692pub const CONTRATO_KEY_DE: &str = "de";
8693
8694/// Canonical camelCase JSON/YAML top-level key for the
8695/// [`crate::aplicacao::WitContract`] struct's `para` per-entry
8696/// target-endpoint-of-the-contract axis. Peer of [`CONTRATO_KEY_DE`] on
8697/// the same [`crate::aplicacao::WitContract`] per-entry serialized-key
8698/// axis; see [`CONTRATO_KEY_DE`] for the full lift rationale. The Rust
8699/// field is lowercase `para`; `#[serde(rename_all = "camelCase")]` is a
8700/// no-op on this axis and the emitted key equals the source-side field
8701/// name byte-for-byte.
8702pub const CONTRATO_KEY_PARA: &str = "para";
8703
8704/// Canonical camelCase JSON/YAML top-level key for the
8705/// [`crate::aplicacao::WitContract`] struct's `wit` per-entry
8706/// WIT-world-reference-of-the-contract axis — the discriminator every
8707/// downstream WIT-shape dispatcher ([`crate::wit_shape_is_http`] /
8708/// [`crate::wit_shape_is_pubsub`] / [`crate::wit_shape_is_store`], the
8709/// future M4 per-edge WIT registry resolver, the future
8710/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission-time
8711/// WIT-world classification) keys off. Peer of [`CONTRATO_KEY_DE`] on
8712/// the same [`crate::aplicacao::WitContract`] per-entry serialized-key
8713/// axis; see [`CONTRATO_KEY_DE`] for the full lift rationale. The Rust
8714/// field is lowercase `wit`; `#[serde(rename_all = "camelCase")]` is a
8715/// no-op on this axis and the emitted key equals the source-side field
8716/// name byte-for-byte.
8717pub const CONTRATO_KEY_WIT: &str = "wit";
8718
8719/// Canonical camelCase YAML sub-key for the [`crate::aplicacao::Placement`]
8720/// struct's `estrategia` distribution-strategy discriminator — the
8721/// per-`M3_KEY_PLACEMENT`-block field the M3 [`crate::aplicacao::PlacementStrategy`]
8722/// enum's `Serialize` derive emits, and the exact scalar every downstream
8723/// consumer dispatches on:
8724///
8725/// - the `lareira-fleet-programs` aggregator's per-entry strategy dispatch
8726///   (each `programs[].placement.estrategia` reads `"SingleNode"` /
8727///   `"Replicated"` / `"Sharded"` verbatim to select the takeover
8728///   semantics per MESH-COMPOSITION.md §II.1),
8729/// - the future `app-operator` reconciler's per-Aplicacao strategy branch,
8730/// - the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
8731///   admission-time `spec.placement.estrategia` typed-enum bind,
8732/// - and every M3 Adaptive weighting the compression pass reads off
8733///   `placement.estrategia` per MESH-COMPOSITION.md §V.
8734///
8735/// The scalar is derived by [`crate::aplicacao::Placement`]'s
8736/// `#[serde(rename_all = "camelCase")]` from the Rust field name
8737/// `estrategia`; `estrategia` has no `_`, so the serde transform is a
8738/// no-op on this axis and the emitted key equals the source-side field
8739/// name byte-for-byte. Lifting the byte to one `&'static str` closes
8740/// the drift footgun structurally: a future refactor renaming the Rust
8741/// field (`estrategia` → `strategy` for English-uniformity, `distribution`
8742/// for schema-clarity, etc.) OR retaining the field name while adding
8743/// a `#[serde(rename = "…")]` override would silently emit a
8744/// `placement:` block whose distribution-strategy discriminator lands
8745/// under one key while every downstream consumer still probes another —
8746/// the aggregator's dispatch, the operator's reconcile, the CR
8747/// materializer's admission bind would each silently no-op, and the
8748/// workload would silently come up under the strategy's serde-derived
8749/// default rather than the per-Aplicacao override the typed slot set.
8750/// The identity pin + serde round-trip pin the sweep introduces catch
8751/// the drift at caixa-core / caixa-mesh build time rather than at the
8752/// aggregator's filter step or the operator's reconcile posture, far
8753/// from the rebrand commit's source.
8754///
8755/// Peer of [`M3_KEY_PLACEMENT`] on the same programs.yaml per-entry
8756/// axis — that constant names the top-level overlay key the entry
8757/// carries, this one names the per-`placement:` sub-block strategy
8758/// discriminator every consumer dispatches on. Byte-identical to (but
8759/// semantically distinct from) [`crate::supervisor::SupervisorSpec`]'s
8760/// peer `estrategia` field on the M2 supervisor-strategy axis — that
8761/// axis carries [`crate::supervisor::RestartStrategy`] (`OneForOne` /
8762/// `OneForAll` / `RestForOne` / `SimpleOneForOne`, OTP supervisor
8763/// semantics) while this axis carries [`crate::aplicacao::PlacementStrategy`]
8764/// (`SingleNode` / `Replicated` / `Sharded`, cross-cluster distribution
8765/// semantics); splitting the two lets each schema's future rebrand
8766/// land independently on the same byte-identical-but-semantically-
8767/// distinct discipline the [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`]
8768/// split established.
8769pub const M3_PLACEMENT_KEY_ESTRATEGIA: &str = "estrategia";
8770
8771/// Canonical camelCase YAML sub-key for the [`crate::aplicacao::Placement`]
8772/// struct's `clusters` cluster-pool axis — the per-`M3_KEY_PLACEMENT`-block
8773/// field carrying the validated cluster-list (non-empty + duplicate-free
8774/// per [`crate::aplicacao::AplicacaoSpec::validate_placement`]) that every
8775/// downstream cross-cluster consumer filters off:
8776///
8777/// - the `lareira-fleet-programs` aggregator's per-cluster fanout filter
8778///   (each cluster's aggregator scopes `.Values.programs` by
8779///   `.placement.clusters | contains .Values.cluster`, so a workload's
8780///   `clusters: [rio, mar]` list ends up landing on rio + mar and no other
8781///   cluster per MESH-COMPOSITION.md §III.4),
8782/// - the future `app-operator` reconciler's per-Aplicacao cluster-set
8783///   dispatch,
8784/// - the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
8785///   admission-time `spec.placement.clusters` typed-list bind, and
8786/// - the M3 Adaptive compression pass's per-cluster weight lookup per
8787///   MESH-COMPOSITION.md §V.
8788///
8789/// The scalar is derived by [`crate::aplicacao::Placement`]'s
8790/// `#[serde(rename_all = "camelCase")]` from the Rust field name
8791/// `clusters`; `clusters` has no `_`, so the serde transform is a no-op
8792/// on this axis and the emitted key equals the source-side field name
8793/// byte-for-byte. Lifting the byte to one `&'static str` closes the same
8794/// drift footgun the peer [`M3_PLACEMENT_KEY_ESTRATEGIA`] lift closed on
8795/// the sibling distribution-strategy discriminator: a future refactor
8796/// renaming the Rust field (`clusters` → `clusterPool` for schema-clarity,
8797/// `sites` for eventual multi-substrate reach, etc.) OR retaining the
8798/// field name while adding a `#[serde(rename = "…")]` override would
8799/// silently emit a `placement:` block whose cluster-list lands under one
8800/// key while every downstream consumer still probes another — the
8801/// aggregator's per-cluster fanout filter would then see an empty
8802/// `clusters` list on every entry and silently drop every workload from
8803/// every cluster (the failure surfacing as "the newly-deployed Aplicacao
8804/// never spins up anywhere" far from the rebrand commit's source). The
8805/// identity pin + serde-derive round-trip pin the sweep introduces catch
8806/// the drift at caixa-core / caixa-mesh build time rather than at the
8807/// aggregator's fanout step or the operator's reconcile posture.
8808///
8809/// Peer of [`M3_KEY_PLACEMENT`] / [`M3_PLACEMENT_KEY_ESTRATEGIA`] on the
8810/// same programs.yaml per-entry axis — `M3_KEY_PLACEMENT` names the
8811/// top-level overlay key each entry carries, `M3_PLACEMENT_KEY_ESTRATEGIA`
8812/// names the per-sub-block distribution-strategy discriminator every
8813/// dispatch consumer branches on, this constant names the per-sub-block
8814/// cluster-pool list every per-cluster fanout consumer scopes by.
8815pub const M3_PLACEMENT_KEY_CLUSTERS: &str = "clusters";
8816
8817/// Canonical camelCase YAML sub-key for the [`crate::aplicacao::Placement`]
8818/// struct's `affinity` placement-engine-hint axis — the per-`M3_KEY_PLACEMENT`-
8819/// block optional field carrying the validated non-empty affinity hint
8820/// (per [`crate::aplicacao::AplicacaoSpec::validate_placement`]) that every
8821/// downstream placement-hint consumer weights off:
8822///
8823/// - the `lareira-fleet-programs` aggregator's per-entry M3 Adaptive
8824///   compression pass reading `placement.affinity` to weight the emitted
8825///   `ComputeUnit`'s replica-distribution overlay per MESH-COMPOSITION.md §V,
8826/// - the future `app-operator` reconciler's per-Aplicacao pod-affinity /
8827///   node-affinity K8s-primitive materializer keying off the same value as
8828///   an `app.pleme.io/affinity-hint=<value>` label selector,
8829/// - the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
8830///   admission-time `spec.placement.affinity` typed-string bind, and
8831/// - the M4 cross-cluster placement engine's per-hint takeover-priority
8832///   dispatch on the same value (`data-locality` / `low-latency` /
8833///   `anti-affinity` per the [`crate::aplicacao::validate_placement_affinity`]
8834///   value-shape gate's documented canonical hint set).
8835///
8836/// The scalar is derived by [`crate::aplicacao::Placement`]'s
8837/// `#[serde(rename_all = "camelCase")]` from the Rust field name
8838/// `affinity`; `affinity` has no `_`, so the serde transform is a no-op on
8839/// this axis and the emitted key equals the source-side field name
8840/// byte-for-byte. Unlike the always-emitted [`M3_PLACEMENT_KEY_ESTRATEGIA`]
8841/// / [`M3_PLACEMENT_KEY_CLUSTERS`] axes, the `affinity` field carries a
8842/// `#[serde(skip_serializing_if = "Option::is_none")]` attribute so the
8843/// key appears in the rendered `placement:` block iff the typed slot
8844/// resolves to `Some(_)` — the omit-when-unset contract the peer typed
8845/// slots ([`crate::aplicacao::MeshPolicy::timeout`],
8846/// [`crate::aplicacao::MeshPolicy::retries`],
8847/// [`crate::aplicacao::MeshPolicy::mtls_required`]) each carry to keep an
8848/// unset typed slot from bloating every rendered programs.yaml entry with
8849/// a nominal-only `affinity: null` value the downstream weighting passes
8850/// would then need to unwrap defensively.
8851///
8852/// Lifting the byte to one `&'static str` closes the same drift footgun
8853/// the peer [`M3_PLACEMENT_KEY_ESTRATEGIA`] / [`M3_PLACEMENT_KEY_CLUSTERS`]
8854/// lifts closed on the sibling always-emitted axes: a future refactor
8855/// renaming the Rust field (`affinity` → `affinityHint` for schema-clarity,
8856/// `placementHint` for symmetry with the future per-cluster affinity
8857/// hierarchy, etc.) OR retaining the field name while adding a
8858/// `#[serde(rename = "…")]` override would silently emit a `placement:`
8859/// block whose affinity hint lands under one key while every downstream
8860/// weighting consumer still probes another — the M3 Adaptive compression
8861/// pass would then see a `None` affinity on every entry and silently fall
8862/// back to the uniform-weight baseline (the workload's typed
8863/// `:affinity "data-locality"` hint would be silently discarded, and the
8864/// failure surfaces as "the newly-deployed Aplicacao's replicas don't
8865/// cluster where the typed slot said they should" far from the rebrand
8866/// commit's source). The identity pin + serde-derive round-trip pin the
8867/// sweep introduces catch the drift at caixa-core / caixa-mesh build time
8868/// rather than at the aggregator's weighting step or the operator's
8869/// reconcile posture.
8870///
8871/// Peer of [`M3_KEY_PLACEMENT`] / [`M3_PLACEMENT_KEY_ESTRATEGIA`] /
8872/// [`M3_PLACEMENT_KEY_CLUSTERS`] on the same programs.yaml per-entry
8873/// axis — `M3_KEY_PLACEMENT` names the top-level overlay key each entry
8874/// carries, `M3_PLACEMENT_KEY_ESTRATEGIA` names the per-sub-block
8875/// distribution-strategy discriminator every dispatch consumer branches
8876/// on, `M3_PLACEMENT_KEY_CLUSTERS` names the per-sub-block cluster-pool
8877/// list every per-cluster fanout consumer scopes by, this constant names
8878/// the per-sub-block optional placement-engine hint every weighting
8879/// consumer reads off.
8880pub const M3_PLACEMENT_KEY_AFFINITY: &str = "affinity";
8881
8882/// Canonical camelCase YAML sub-key for the [`crate::aplicacao::Placement`]
8883/// struct's `shard_key` shard-selection-template axis — the per-`M3_KEY_PLACEMENT`-
8884/// block optional field carrying the validated non-empty shard-key
8885/// template (per [`crate::aplicacao::AplicacaoSpec::validate_placement`]'s
8886/// `ShardedKeyEmpty` arm — the build rejects any `:placement Sharded`
8887/// that omits the slot, and rejects any non-Sharded strategy that
8888/// carries the slot as `ShardKeyOnNonSharded`) that every downstream
8889/// shard-dispatch consumer materializes off:
8890///
8891/// - the `lareira-fleet-programs` aggregator's per-entry M3 shard-pool
8892///   dispatch materializer keying off `placement.shardKey` to hash each
8893///   incoming entity into the per-cluster shard pool the Akka-style
8894///   cluster-sharding reconciler owns (per MESH-COMPOSITION.md §II.4);
8895/// - the future `app-operator` reconciler's per-Aplicacao
8896///   `ShardedResource` CR emitter binding the typed template to the
8897///   K8s-primitive shard-assignment controller's `spec.hashKey`;
8898/// - the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
8899///   admission-time `spec.placement.shardKey` typed-string bind, and
8900/// - the M4 Orleans-style virtual-actor runtime's per-grain
8901///   placement dispatch reading the same value as the grain-identity
8902///   hash source (per RUNTIME-PATTERNS.md's virtual-actor pattern
8903///   entry).
8904///
8905/// The scalar is derived by [`crate::aplicacao::Placement`]'s
8906/// `#[serde(rename_all = "camelCase")]` from the Rust field name
8907/// `shard_key`; unlike the peer `affinity` / `clusters` / `estrategia`
8908/// axes (whose field names carry no `_`, so the serde transform is a
8909/// no-op), the `shard_key` field's `snake_case` name is actively
8910/// transformed by the derive to `shardKey` — the emitted key differs
8911/// from the source-side field name and the drift-footgun surface is
8912/// therefore correspondingly larger. Unlike the always-emitted
8913/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] / [`M3_PLACEMENT_KEY_CLUSTERS`]
8914/// axes, the `shard_key` field carries a
8915/// `#[serde(skip_serializing_if = "Option::is_none")]` attribute so the
8916/// key appears in the rendered `placement:` block iff the typed slot
8917/// resolves to `Some(_)` — the omit-when-unset contract the peer typed
8918/// slots ([`M3_PLACEMENT_KEY_AFFINITY`],
8919/// [`crate::aplicacao::MeshPolicy::timeout`],
8920/// [`crate::aplicacao::MeshPolicy::retries`],
8921/// [`crate::aplicacao::MeshPolicy::mtls_required`]) each carry to keep
8922/// an unset typed slot from bloating every rendered programs.yaml
8923/// entry with a nominal-only `shardKey: null` value the downstream
8924/// shard-dispatch passes would then need to unwrap defensively.
8925///
8926/// Lifting the byte to one `&'static str` closes the same drift footgun
8927/// the peer [`M3_PLACEMENT_KEY_ESTRATEGIA`] / [`M3_PLACEMENT_KEY_CLUSTERS`]
8928/// / [`M3_PLACEMENT_KEY_AFFINITY`] lifts closed on the sibling axes:
8929/// a future refactor renaming the Rust field (`shard_key` →
8930/// `partition_key` for Kafka-symmetric naming, `entity_key` for
8931/// Akka/Orleans-symmetric naming, `hash_key` for schema-clarity, etc.)
8932/// OR retaining the field name while adding a `#[serde(rename = "…")]`
8933/// override OR dropping the struct-level `rename_all = "camelCase"`
8934/// attribute would silently emit a `placement:` block whose shard-
8935/// selection template lands under one key while every downstream shard-
8936/// dispatch consumer still probes another — the M3 shard-pool
8937/// dispatch materializer would then see a `None` shard-key on every
8938/// entry and silently fall back to the per-entry random-placement
8939/// baseline (the workload's typed `:shard-key "$tenantId"` template
8940/// would be silently discarded, and per-tenant entities would scatter
8941/// across every cluster in the pool instead of consistently landing on
8942/// one — the failure surfaces as "the newly-deployed sharded Aplicacao
8943/// mysteriously loses its per-tenant locality" far from the rebrand
8944/// commit's source, and Cilium's per-entity trace surfaces the
8945/// symptom only in hubble traces of the actual data-plane skew, not in
8946/// `kubectl describe`). The identity pin + serde-derive round-trip
8947/// pin the sweep introduces catch the drift at caixa-core / caixa-mesh
8948/// build time rather than at the aggregator's shard-dispatch step or
8949/// the operator's reconcile posture. The serde-derive pin is
8950/// particularly load-bearing on this axis (relative to the peer
8951/// `affinity` / `clusters` / `estrategia` pins) because the underlying
8952/// derive transform is *not* a no-op — the emitted `shardKey` key
8953/// differs from the source-side `shard_key` field by construction,
8954/// so any rebrand that touches either endpoint of the transform (the
8955/// field name OR the `rename_all` attribute OR a per-field `rename`
8956/// override) reaches this pin's assertion by construction.
8957///
8958/// Peer of [`M3_KEY_PLACEMENT`] / [`M3_PLACEMENT_KEY_ESTRATEGIA`] /
8959/// [`M3_PLACEMENT_KEY_CLUSTERS`] / [`M3_PLACEMENT_KEY_AFFINITY`] on the
8960/// same programs.yaml per-entry axis — `M3_KEY_PLACEMENT` names the
8961/// top-level overlay key each entry carries, `M3_PLACEMENT_KEY_ESTRATEGIA`
8962/// names the per-sub-block distribution-strategy discriminator every
8963/// dispatch consumer branches on, `M3_PLACEMENT_KEY_CLUSTERS` names the
8964/// per-sub-block cluster-pool list every per-cluster fanout consumer
8965/// scopes by, `M3_PLACEMENT_KEY_AFFINITY` names the per-sub-block
8966/// optional placement-engine hint every weighting consumer reads off,
8967/// this constant names the per-sub-block optional shard-selection
8968/// template every shard-dispatch consumer materializes off. Completes
8969/// the M3 `Placement` sub-key quartet's canonical-key lift alongside
8970/// the sibling always-emitted axes.
8971pub const M3_PLACEMENT_KEY_SHARD_KEY: &str = "shardKey";
8972
8973/// Canonical M3 [`crate::aplicacao::PlacementStrategy::SingleNode`]
8974/// variant discriminator scalar-value — the exact byte-string the
8975/// `Serialize` derive on the un-`rename`d enum emits under
8976/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] whenever the typed slot's
8977/// distribution strategy is the single-cluster-active-at-a-time arm
8978/// (OTP distributed-application takeover, MESH-COMPOSITION.md §II.1).
8979///
8980/// The scalar every downstream cluster-side dispatcher probes verbatim
8981/// to pick the takeover semantics:
8982///
8983/// - the `lareira-fleet-programs` aggregator's per-entry
8984///   `placement.estrategia` strategy dispatch (`if $strat ==
8985///   "SingleNode" { ... }`),
8986/// - the future `app-operator` reconciler's per-Aplicacao
8987///   strategy-branch (`match placement.estrategia { "SingleNode" =>
8988///   … }`),
8989/// - the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
8990///   admission-time enum-arm bind, and
8991/// - the M3 Adaptive compression pass's per-strategy weighting per
8992///   MESH-COMPOSITION.md §V.
8993///
8994/// The scalar is derived by `#[derive(Serialize)]` on the
8995/// [`crate::aplicacao::PlacementStrategy`] enum with no
8996/// `#[serde(rename_all = …)]` attribute, so the emitted string is
8997/// byte-for-byte the source-side variant name. Lifting the byte to
8998/// one `&'static str` closes the drift footgun structurally: a future
8999/// refactor renaming the variant (`SingleNode` → `Singleton` for OTP-
9000/// vocabulary parity, `Active` for shorter-form-clarity, etc.) OR
9001/// adding a `#[serde(rename_all = "kebab-case")]` attribute would
9002/// silently emit a `placement.estrategia:` scalar whose distribution
9003/// strategy lands under one spelling while every downstream consumer
9004/// still dispatches on another — the aggregator's strategy branch,
9005/// the operator's reconcile posture, the CR materializer's
9006/// admission-time enum-arm bind would each silently no-op onto the
9007/// enum's `default()` (`Replicated`) and the workload would come up
9008/// on every declared cluster active-active rather than the
9009/// single-cluster-takeover the typed slot named. The serde
9010/// round-trip pin the sweep introduces
9011/// ([`crate::aplicacao::tests::placement_strategy_variants_serialize_to_lifted_scalar_values`])
9012/// catches the drift at caixa-core build time rather than at the
9013/// aggregator's dispatch step or the operator's reconcile posture.
9014///
9015/// Peer of [`M3_PLACEMENT_ESTRATEGIA_REPLICATED`] /
9016/// [`M3_PLACEMENT_ESTRATEGIA_SHARDED`] on the same closed
9017/// PlacementStrategy enum surface — together the three constants
9018/// name every author-reachable arm of the M3 distribution-strategy
9019/// discriminator, mirroring the closed-enum-scalar-value trajectory
9020/// [`CILIUM_AUTH_MODE_REQUIRED`] / [`CILIUM_AUTH_MODE_DISABLED`]
9021/// (8ab119f) established on the sibling Cilium
9022/// `MutualAuthenticationMode` OpenAPI schema enum.
9023pub const M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE: &str = "SingleNode";
9024
9025/// Canonical M3 [`crate::aplicacao::PlacementStrategy::Replicated`]
9026/// variant discriminator scalar-value — the exact byte-string the
9027/// `Serialize` derive on the un-`rename`d enum emits under
9028/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] whenever the typed slot's
9029/// distribution strategy is the every-cluster-active-active arm (the
9030/// enum's `default()` and the canonical happy-path per
9031/// MESH-COMPOSITION.md §II.1).
9032///
9033/// Peer of the sibling [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`] /
9034/// [`M3_PLACEMENT_ESTRATEGIA_SHARDED`] scalars on the same closed
9035/// enum surface — see the sibling doc for the full drift-mode
9036/// analysis. This is the arm the un-`:placement` (`Placement::default()`)
9037/// path serializes as, so drift here silently rebrands the substrate's
9038/// default distribution posture across every Aplicacao that never
9039/// declares the slot explicitly.
9040pub const M3_PLACEMENT_ESTRATEGIA_REPLICATED: &str = "Replicated";
9041
9042/// Canonical M3 [`crate::aplicacao::PlacementStrategy::Sharded`]
9043/// variant discriminator scalar-value — the exact byte-string the
9044/// `Serialize` derive on the un-`rename`d enum emits under
9045/// [`M3_PLACEMENT_KEY_ESTRATEGIA`] whenever the typed slot's
9046/// distribution strategy is the hash-keyed-across-clusters arm (Akka
9047/// cluster sharding, MESH-COMPOSITION.md §II.4). The one arm on which
9048/// the typed [`M3_PLACEMENT_KEY_SHARD_KEY`] sub-block is required —
9049/// `AplicacaoSpec::validate_placement` gates `shard_key.is_some() ==
9050/// matches!(estrategia, Sharded)` as a structural partition of every
9051/// validated [`crate::aplicacao::Placement`].
9052///
9053/// Peer of the sibling [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`] /
9054/// [`M3_PLACEMENT_ESTRATEGIA_REPLICATED`] scalars on the same closed
9055/// enum surface — see the [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`] doc
9056/// for the full drift-mode analysis. This is the arm the future Akka-
9057/// style cluster-sharding reconciler dispatches on before hashing
9058/// `placement.shardKey` across `placement.clusters`, so drift here
9059/// silently collapses the hash-keyed distribution back onto the
9060/// aggregator's default (Replicated) and every sharded workload's
9061/// per-entity routing invariant vanishes at the data plane.
9062pub const M3_PLACEMENT_ESTRATEGIA_SHARDED: &str = "Sharded";
9063
9064/// Canonical M2 [`crate::supervisor::RestartStrategy::OneForOne`] variant
9065/// discriminator scalar-value — the exact byte-string the `Serialize`
9066/// derive on the un-`rename`d enum emits under
9067/// [`SUPERVISOR_KEY_ESTRATEGIA`] whenever the typed `:supervisor
9068/// :estrategia` slot's strategy is the restart-only-the-failed-child arm
9069/// (the enum's `default()` and the canonical happy-path per
9070/// theory/INSPIRATIONS.md §II.2 — Erlang/OTP `one_for_one`).
9071///
9072/// The scalar is the un-`rename`d Rust variant name verbatim; a future
9073/// `#[serde(rename_all = "kebab-case")]` attribute on the enum, or a
9074/// per-variant `#[serde(rename = "…")]` override, or a variant rename in
9075/// the source, would silently emit a `:supervisor :estrategia` scalar
9076/// whose per-failure sibling-restart discipline lands under one spelling
9077/// while every downstream consumer still dispatches on another — the
9078/// future wasm-operator's per-supervisor sibling-restart branch, the
9079/// future M4 `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's
9080/// admission-time enum-arm bind, the `caixa-operator`'s hierarchical
9081/// reconciliation scheduler's per-strategy fan-out would each silently
9082/// no-op onto the enum's `default()` (`OneForOne`) and the tree would
9083/// come up with the wrong sibling-restart posture on every non-default
9084/// arm. The serde round-trip pin the sweep introduces
9085/// ([`crate::supervisor::tests::restart_strategy_variants_serialize_to_lifted_scalar_values`])
9086/// catches the drift at caixa-core build time rather than at the
9087/// operator's reconcile posture.
9088///
9089/// Peer of [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ALL`] /
9090/// [`SUPERVISOR_ESTRATEGIA_REST_FOR_ONE`] /
9091/// [`SUPERVISOR_ESTRATEGIA_SIMPLE_ONE_FOR_ONE`] on the same closed
9092/// [`crate::supervisor::RestartStrategy`] enum surface — together the
9093/// four constants name every author-reachable arm of the OTP-shaped
9094/// per-supervisor sibling-restart discriminator, mirroring the
9095/// closed-enum-scalar-value trajectory [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`]
9096/// / [`M3_PLACEMENT_ESTRATEGIA_REPLICATED`] /
9097/// [`M3_PLACEMENT_ESTRATEGIA_SHARDED`] (3f0e21c) established on the
9098/// sibling M3 `PlacementStrategy` enum on the peer per-Aplicacao
9099/// distribution-strategy axis.
9100pub const SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE: &str = "OneForOne";
9101
9102/// Canonical M2 [`crate::supervisor::RestartStrategy::OneForAll`] variant
9103/// discriminator scalar-value — the exact byte-string the `Serialize`
9104/// derive on the un-`rename`d enum emits under
9105/// [`SUPERVISOR_KEY_ESTRATEGIA`] whenever the typed `:supervisor
9106/// :estrategia` slot's strategy is the restart-every-sibling-on-any-
9107/// failure arm (Erlang/OTP `one_for_all`, used when children share state
9108/// and must be in sync).
9109///
9110/// Peer of the sibling [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] /
9111/// [`SUPERVISOR_ESTRATEGIA_REST_FOR_ONE`] /
9112/// [`SUPERVISOR_ESTRATEGIA_SIMPLE_ONE_FOR_ONE`] scalars on the same
9113/// closed enum surface — see the sibling
9114/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] doc for the full drift-mode
9115/// analysis.
9116pub const SUPERVISOR_ESTRATEGIA_ONE_FOR_ALL: &str = "OneForAll";
9117
9118/// Canonical M2 [`crate::supervisor::RestartStrategy::RestForOne`]
9119/// variant discriminator scalar-value — the exact byte-string the
9120/// `Serialize` derive on the un-`rename`d enum emits under
9121/// [`SUPERVISOR_KEY_ESTRATEGIA`] whenever the typed `:supervisor
9122/// :estrategia` slot's strategy is the restart-failed-and-later-started-
9123/// siblings arm (Erlang/OTP `rest_for_one`, used when later children
9124/// depend on earlier ones so the startup-order suffix must be
9125/// re-established).
9126///
9127/// Peer of the sibling [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] /
9128/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ALL`] /
9129/// [`SUPERVISOR_ESTRATEGIA_SIMPLE_ONE_FOR_ONE`] scalars on the same
9130/// closed enum surface — see the sibling
9131/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] doc for the full drift-mode
9132/// analysis.
9133pub const SUPERVISOR_ESTRATEGIA_REST_FOR_ONE: &str = "RestForOne";
9134
9135/// Canonical M2 [`crate::supervisor::RestartStrategy::SimpleOneForOne`]
9136/// variant discriminator scalar-value — the exact byte-string the
9137/// `Serialize` derive on the un-`rename`d enum emits under
9138/// [`SUPERVISOR_KEY_ESTRATEGIA`] whenever the typed `:supervisor
9139/// :estrategia` slot's strategy is the dynamic-children-of-one-shape arm
9140/// (Erlang/OTP `simple_one_for_one`, the one arm on which
9141/// [`crate::supervisor::SupervisorSpec::validate`] gates
9142/// `children.is_empty()` as a structural partition — static `:children`
9143/// on a `SimpleOneForOne` supervisor is a build-time rejection).
9144///
9145/// Peer of the sibling [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] /
9146/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ALL`] /
9147/// [`SUPERVISOR_ESTRATEGIA_REST_FOR_ONE`] scalars on the same closed
9148/// enum surface — see the sibling
9149/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] doc for the full drift-mode
9150/// analysis.
9151pub const SUPERVISOR_ESTRATEGIA_SIMPLE_ONE_FOR_ONE: &str = "SimpleOneForOne";
9152
9153/// Canonical M2 [`crate::supervisor::RestartPolicy::Permanent`] variant
9154/// discriminator scalar-value — the exact byte-string the `Serialize`
9155/// derive on the un-`rename`d enum emits under
9156/// [`SUPERVISOR_CHILD_KEY_RESTART`] whenever the typed `:children :restart`
9157/// per-child restart-policy slot is the always-restart-regardless-of-exit
9158/// arm (the enum's `default()` and the canonical happy-path per
9159/// theory/INSPIRATIONS.md §II.2 — Erlang/OTP `permanent`, the
9160/// long-running-service posture where the supervisor must bring the
9161/// child back on every failure mode).
9162///
9163/// The scalar is the un-`rename`d Rust variant name verbatim; a future
9164/// `#[serde(rename_all = "kebab-case")]` attribute on the enum, or a
9165/// per-variant `#[serde(rename = "…")]` override, or a variant rename in
9166/// the source, would silently emit a `:children :restart` scalar
9167/// whose per-exit restart-decision discipline lands under one spelling
9168/// while every downstream consumer still dispatches on another — the
9169/// future wasm-operator's per-child restart-decision branch, the future
9170/// M4 `mesh.pleme.io/v1alpha1/Supervisor` CR materializer's
9171/// admission-time enum-arm bind, the `caixa-operator`'s hierarchical
9172/// reconciliation scheduler's per-child-policy fan-out would each silently
9173/// no-op onto the enum's `default()` (`Permanent`) and children would
9174/// come up with the wrong per-exit restart posture on every non-default
9175/// arm — a `:temporary` `oneShot` child would be restarted on clean
9176/// exit (the successful-completion signal treated as failure), a
9177/// `:transient` child that clean-exited would be restarted (masking the
9178/// clean-completion contract), and the operator's post-exit dispatch
9179/// would silently degrade to the always-restart posture. The serde
9180/// round-trip pin the sweep introduces
9181/// ([`crate::supervisor::tests::restart_policy_variants_serialize_to_lifted_scalar_values`])
9182/// catches the drift at caixa-core build time rather than at the
9183/// operator's reconcile posture.
9184///
9185/// Peer of [`SUPERVISOR_CHILD_RESTART_TEMPORARY`] /
9186/// [`SUPERVISOR_CHILD_RESTART_TRANSIENT`] on the same closed
9187/// [`crate::supervisor::RestartPolicy`] enum surface — together the
9188/// three constants name every author-reachable arm of the OTP-shaped
9189/// per-child restart-decision discriminator, mirroring the
9190/// closed-enum-scalar-value trajectory
9191/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ONE`] /
9192/// [`SUPERVISOR_ESTRATEGIA_ONE_FOR_ALL`] /
9193/// [`SUPERVISOR_ESTRATEGIA_REST_FOR_ONE`] /
9194/// [`SUPERVISOR_ESTRATEGIA_SIMPLE_ONE_FOR_ONE`] (09ffb2d) established on
9195/// the sibling `RestartStrategy` enum on the peer per-supervisor
9196/// sibling-restart-strategy axis and [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`]
9197/// / [`M3_PLACEMENT_ESTRATEGIA_REPLICATED`] /
9198/// [`M3_PLACEMENT_ESTRATEGIA_SHARDED`] (3f0e21c) established on the M3
9199/// `PlacementStrategy` enum on the peer per-Aplicacao distribution-strategy
9200/// axis. The three OTP-shaped closed-enum discriminator axes on the
9201/// caixa typed surface (supervisor sibling-restart strategy, per-child
9202/// restart policy, per-Aplicacao placement strategy) now each carry the
9203/// same three-path-convergence (`Serialize` derive → `as_str` helper →
9204/// lifted constant) drift-detection posture.
9205pub const SUPERVISOR_CHILD_RESTART_PERMANENT: &str = "Permanent";
9206
9207/// Canonical M2 [`crate::supervisor::RestartPolicy::Temporary`] variant
9208/// discriminator scalar-value — the exact byte-string the `Serialize`
9209/// derive on the un-`rename`d enum emits under
9210/// [`SUPERVISOR_CHILD_KEY_RESTART`] whenever the typed `:children :restart`
9211/// per-child restart-policy slot is the never-restart arm (Erlang/OTP
9212/// `temporary`, the one-shot posture where the child's completion — clean
9213/// or not — is itself the success signal; the `oneShot`
9214/// [`crate::render::COMPUTEUNIT_SPEC_KEY_TRIGGER`] arm maps here).
9215///
9216/// Peer of the sibling [`SUPERVISOR_CHILD_RESTART_PERMANENT`] /
9217/// [`SUPERVISOR_CHILD_RESTART_TRANSIENT`] scalars on the same
9218/// closed enum surface — see the sibling
9219/// [`SUPERVISOR_CHILD_RESTART_PERMANENT`] doc for the full drift-mode
9220/// analysis.
9221pub const SUPERVISOR_CHILD_RESTART_TEMPORARY: &str = "Temporary";
9222
9223/// Canonical M2 [`crate::supervisor::RestartPolicy::Transient`] variant
9224/// discriminator scalar-value — the exact byte-string the `Serialize`
9225/// derive on the un-`rename`d enum emits under
9226/// [`SUPERVISOR_CHILD_KEY_RESTART`] whenever the typed `:children :restart`
9227/// per-child restart-policy slot is the restart-only-on-abnormal-exit arm
9228/// (Erlang/OTP `transient`, the "restart on non-zero exit or unhandled
9229/// exception; a clean exit completes the child" posture — the third
9230/// canonical OTP per-child restart-decision arm alongside `permanent`
9231/// and `temporary`).
9232///
9233/// Peer of the sibling [`SUPERVISOR_CHILD_RESTART_PERMANENT`] /
9234/// [`SUPERVISOR_CHILD_RESTART_TEMPORARY`] scalars on the same
9235/// closed enum surface — see the sibling
9236/// [`SUPERVISOR_CHILD_RESTART_PERMANENT`] doc for the full drift-mode
9237/// analysis.
9238pub const SUPERVISOR_CHILD_RESTART_TRANSIENT: &str = "Transient";
9239
9240/// Canonical camelCase JSON/YAML top-level key for the
9241/// [`crate::aplicacao::Entrada`] struct's `host` external-hostname axis —
9242/// the `host:` field the M3 Aplicacao's `#[serde(rename_all = "camelCase")]`
9243/// derive on [`crate::aplicacao::Entrada`] emits at the singleton
9244/// `:entrada` block, and the exact scalar every downstream consumer
9245/// reaching for the external hostname via `Value::get(...)` (the
9246/// [`caixa_mesh`] Gateway/HTTPRoute emitter's per-Aplicacao
9247/// `spec.hostnames` projection under [`GATEWAY_API_KEY_HOSTNAME`] /
9248/// [`GATEWAY_API_KEY_HOSTNAMES`], the future `app-operator`
9249/// reconciler's per-Aplicacao ingress-hostname bind, the future
9250/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission-time
9251/// hostname cross-check against the cluster's declared
9252/// [`GATEWAY_API_HOSTNAME_MAX_LEN`] discipline) must probe on.
9253///
9254/// The scalar is derived from the Rust field name `host` by the
9255/// `rename_all = "camelCase"` derive; `host` has no `_`, so the serde
9256/// transform is a no-op on this axis and the emitted key equals the
9257/// source-side field name byte-for-byte. Lifting the byte to one
9258/// `&'static str` closes the drift footgun structurally: a future
9259/// refactor renaming the Rust field OR retaining the field name while
9260/// adding a `#[serde(rename = "…")]` override would silently emit an
9261/// `Entrada` whose external-hostname discriminator lands under one key
9262/// while every downstream consumer still probes another — the Gateway
9263/// emitter's per-Aplicacao hostname projection, the operator's ingress
9264/// bind, the CR materializer's admission-time cross-check would each
9265/// silently fall back to no-hostname and the Gateway API would either
9266/// admit an all-hostname listener (breaking the per-Aplicacao
9267/// host-isolation contract MESH-COMPOSITION.md §III.5 promises) or
9268/// reject the resource outright at admission. The identity pin
9269/// (`entrada_serde_keys_match_lifted_entrada_key_consts` on the
9270/// source-side type) catches drift at caixa-core build time rather than
9271/// at the Gateway controller's admission step, far from the rebrand
9272/// commit's source.
9273///
9274/// Peer of [`ENTRADA_KEY_PARA`] / [`ENTRADA_KEY_PATHS`] /
9275/// [`ENTRADA_KEY_PORT`] on the same [`crate::aplicacao::Entrada`]
9276/// singleton serialized-key axis. Peer of the sibling
9277/// [`MEMBRO_KEY_CAIXA`] / [`MEMBRO_KEY_VERSAO`] pair (ce80ca0) and
9278/// [`CONTRATO_KEY_DE`] / [`CONTRATO_KEY_PARA`] / [`CONTRATO_KEY_WIT`]
9279/// triad (ca463a4) on the sibling M3 per-`:membros` and per-`:contratos`
9280/// entry axes — those lifts pinned the M3 collection-slot atom
9281/// camelCase JSON keys, this lift extends the same discipline onto the
9282/// singleton `:entrada` mesh slot so the last M3 typed-struct
9283/// `#[serde(rename_all = "camelCase")]` axis on the Aplicacao surface
9284/// joins the substrate's "one canonical byte-string per typed
9285/// serialized-key axis" discipline. Same discipline every peer
9286/// camelCase serde-key lift carries ([`M2_LIMITS_KEY_MEMORY`] etc.
9287/// (d8b8b4f), [`M2_BEHAVIOR_KEY_ON_INIT`] etc. (21fe462),
9288/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
9289/// (36ffe65), [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc.,
9290/// [`SUPERVISOR_KEY_ESTRATEGIA`] etc. (40cc4e5)).
9291pub const ENTRADA_KEY_HOST: &str = "host";
9292
9293/// Canonical camelCase JSON/YAML top-level key for the
9294/// [`crate::aplicacao::Entrada`] struct's `para` destination-member axis
9295/// — the `para:` field naming which `:membros` entry the external
9296/// Gateway routes to. Peer of [`ENTRADA_KEY_HOST`] on the same
9297/// [`crate::aplicacao::Entrada`] singleton serialized-key axis; see
9298/// [`ENTRADA_KEY_HOST`] for the full lift rationale. The Rust field is
9299/// lowercase `para`; `#[serde(rename_all = "camelCase")]` is a no-op on
9300/// this axis and the emitted key equals the source-side field name
9301/// byte-for-byte.
9302///
9303/// Byte-identical to [`CONTRATO_KEY_PARA`] today — both resolve to the
9304/// same four-byte `"para"` literal — but semantically distinct:
9305/// [`CONTRATO_KEY_PARA`] names the per-`:contratos` edge's callee-Servico
9306/// discriminator on the [`crate::aplicacao::WitContract`] surface, while
9307/// this constant names the singleton `:entrada` block's Gateway-route
9308/// destination-Servico discriminator on the sibling
9309/// [`crate::aplicacao::Entrada`] surface. Splitting the two lets each
9310/// schema's future rebrand land independently on the same
9311/// "byte-identical-but-semantically-distinct" discipline the peer
9312/// [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAME`] split established
9313/// (935979a) on the sibling per-entry name-discriminator axis and the
9314/// [`FLEET_PROGRAMS_KEY_VERSAO`] / [`MEMBRO_KEY_VERSAO`] split
9315/// established (ce80ca0) on the sibling per-entry version-constraint
9316/// axis.
9317pub const ENTRADA_KEY_PARA: &str = "para";
9318
9319/// Canonical camelCase JSON/YAML top-level key for the
9320/// [`crate::aplicacao::Entrada`] struct's `paths` per-Aplicacao
9321/// path-filter axis — the `paths:` sequence the M3 Aplicacao's
9322/// `#[serde(rename_all = "camelCase")]` derive emits at the singleton
9323/// `:entrada` block, and the exact scalar every downstream
9324/// per-`:entrada :paths` HTTPRoute-match-projection consumer must probe
9325/// on (the [`caixa_mesh`] HTTPRoute emitter's per-Aplicacao `matches[]`
9326/// projection under [`GATEWAY_API_KEY_MATCHES`], defaulting to
9327/// [`GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH`] when the slot is empty per
9328/// 48e2083). Peer of [`ENTRADA_KEY_HOST`] on the same
9329/// [`crate::aplicacao::Entrada`] singleton serialized-key axis; see
9330/// [`ENTRADA_KEY_HOST`] for the full lift rationale. The Rust field is
9331/// lowercase `paths`; `#[serde(rename_all = "camelCase")]` is a no-op
9332/// on this axis and the emitted key equals the source-side field name
9333/// byte-for-byte.
9334pub const ENTRADA_KEY_PATHS: &str = "paths";
9335
9336/// Canonical camelCase JSON/YAML top-level key for the
9337/// [`crate::aplicacao::Entrada`] struct's `port` destination-Servico
9338/// port axis — the `port:` field the M3 Aplicacao's
9339/// `#[serde(rename_all = "camelCase")]` derive emits at the singleton
9340/// `:entrada` block, defaulting via [`crate::aplicacao::default_port`]
9341/// to [`crate::DEFAULT_SERVICO_PORT`] when the author omits the slot.
9342/// Peer of [`ENTRADA_KEY_HOST`] on the same
9343/// [`crate::aplicacao::Entrada`] singleton serialized-key axis; see
9344/// [`ENTRADA_KEY_HOST`] for the full lift rationale. The Rust field is
9345/// lowercase `port`; `#[serde(rename_all = "camelCase")]` is a no-op on
9346/// this axis and the emitted key equals the source-side field name
9347/// byte-for-byte.
9348///
9349/// Byte-identical to [`KUBE_KEY_PORT`] today — both resolve to the same
9350/// four-byte `"port"` literal — but semantically distinct:
9351/// [`KUBE_KEY_PORT`] names the K8s Service/ContainerPort per-resource
9352/// port-discriminator axis, while this constant names the typed
9353/// [`crate::aplicacao::Entrada`] singleton block's Gateway-route
9354/// destination-Servico port axis on the M3 Aplicacao surface.
9355/// Splitting the two lets each schema's future rebrand land
9356/// independently.
9357pub const ENTRADA_KEY_PORT: &str = "port";
9358
9359/// Canonical camelCase JSON/YAML top-level key for the
9360/// [`crate::aplicacao::MeshPolicy`] struct's `timeout` per-call
9361/// wall-clock cap axis — the `timeout:` field the M3 Aplicacao's
9362/// `#[serde(rename_all = "camelCase")]` derive on
9363/// [`crate::aplicacao::MeshPolicy`] emits at the singleton `:politicas`
9364/// block, and the exact scalar every downstream mesh-timeout consumer
9365/// must probe on (the future M4 per-edge `:politicas` overlay
9366/// projection onto Cilium `L7Rules` / Gateway API `HTTPRoute`
9367/// per-backend `timeouts.backendRequest` axis per
9368/// MESH-COMPOSITION.md §III.3, the future
9369/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission-time
9370/// mesh-timeout cross-check, the future `feira lint` per-`:politicas`
9371/// authored-duration bound-check against
9372/// [`crate::POLICY_TIMEOUT_MAX`]).
9373///
9374/// The scalar is derived from the Rust field name `timeout` by the
9375/// `rename_all = "camelCase"` derive; `timeout` has no `_`, so the
9376/// serde transform is a no-op on this axis and the emitted key equals
9377/// the source-side field name byte-for-byte. Lifting the byte to one
9378/// `&'static str` closes the drift footgun structurally: a future
9379/// refactor renaming the Rust field OR retaining the field name while
9380/// adding a `#[serde(rename = "…")]` override would silently emit a
9381/// [`MeshPolicy`][mp] whose per-call timeout discriminator lands under
9382/// one key while every downstream consumer still probes another — the
9383/// M4 per-edge overlay projection, the CR materializer's cross-check,
9384/// the linter's bound-check would each silently fall back to
9385/// no-timeout and every `:contratos`-edge request would silently
9386/// bypass the per-call cap the typed slot set, with the failure
9387/// surfacing as "the mesh no longer enforces the timeout the
9388/// Aplicacao authored" far from the rebrand commit's source. The
9389/// identity pin (`mesh_policy_serde_keys_match_lifted_politicas_key_consts`
9390/// on the source-side type) catches drift at caixa-core build time
9391/// rather than at the mesh controller's reconcile step.
9392///
9393/// [mp]: crate::aplicacao::MeshPolicy
9394///
9395/// Peer of [`POLITICAS_KEY_RETRIES`] / [`POLITICAS_KEY_CIRCUIT_BREAKER`] /
9396/// [`POLITICAS_KEY_MTLS_REQUIRED`] / [`POLITICAS_KEY_RATE_LIMIT`] on the
9397/// same [`crate::aplicacao::MeshPolicy`] singleton serialized-key
9398/// axis. Peer of the sibling [`ENTRADA_KEY_HOST`] etc. tetrad
9399/// (a3d6162), [`M3_PLACEMENT_KEY_ESTRATEGIA`] etc. tetrad,
9400/// [`MEMBRO_KEY_CAIXA`] / [`MEMBRO_KEY_VERSAO`] pair (ce80ca0), and
9401/// [`CONTRATO_KEY_DE`] / [`CONTRATO_KEY_PARA`] / [`CONTRATO_KEY_WIT`]
9402/// triad (ca463a4) on the sibling M3 typed-struct axes — those lifts
9403/// pinned every peer M3 mesh-slot atom, this lift closes the last M3
9404/// typed-struct top-level `#[serde(rename_all = "camelCase")]` axis on
9405/// the Aplicacao surface without a lifted serde-key peer (the
9406/// [`crate::aplicacao::MeshPolicy`] singleton `:politicas` block) so
9407/// the entire M3 typed-struct surface joins the substrate's "one
9408/// canonical byte-string per typed serialized-key axis" discipline.
9409/// Same discipline every peer camelCase serde-key lift carries
9410/// ([`M2_LIMITS_KEY_MEMORY`] etc. (d8b8b4f),
9411/// [`M2_BEHAVIOR_KEY_ON_INIT`] etc. (21fe462),
9412/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
9413/// (36ffe65), [`SUPERVISOR_KEY_ESTRATEGIA`] etc. (40cc4e5)).
9414pub const POLITICAS_KEY_TIMEOUT: &str = "timeout";
9415
9416/// Canonical camelCase JSON/YAML top-level key for the
9417/// [`crate::aplicacao::MeshPolicy`] struct's `retries` transient-failure
9418/// retry-count axis — the `retries:` field the M3 Aplicacao's
9419/// `#[serde(rename_all = "camelCase")]` derive on
9420/// [`crate::aplicacao::MeshPolicy`] emits at the singleton `:politicas`
9421/// block. Peer of [`POLITICAS_KEY_TIMEOUT`] on the same
9422/// [`crate::aplicacao::MeshPolicy`] singleton serialized-key axis; see
9423/// [`POLITICAS_KEY_TIMEOUT`] for the full lift rationale. The Rust
9424/// field is lowercase `retries`; `#[serde(rename_all = "camelCase")]`
9425/// is a no-op on this axis and the emitted key equals the source-side
9426/// field name byte-for-byte.
9427pub const POLITICAS_KEY_RETRIES: &str = "retries";
9428
9429/// Canonical camelCase JSON/YAML top-level key for the
9430/// [`crate::aplicacao::MeshPolicy`] struct's `circuit_breaker`
9431/// circuit-breaker sub-block axis — the `circuitBreaker:` field the M3
9432/// Aplicacao's `#[serde(rename_all = "camelCase")]` derive on
9433/// [`crate::aplicacao::MeshPolicy`] emits at the singleton `:politicas`
9434/// block, and the exact camelCase scalar (Rust field
9435/// `circuit_breaker` → serde-emitted `circuitBreaker`, one of the two
9436/// `MeshPolicy` axes the derive-attribute non-trivially transforms
9437/// alongside [`POLITICAS_KEY_MTLS_REQUIRED`] and
9438/// [`POLITICAS_KEY_RATE_LIMIT`]) every downstream circuit-breaker
9439/// consumer must probe on (the future M4 per-edge `:politicas` overlay
9440/// projection onto the mesh's per-backend failure-counter reset
9441/// window per MESH-COMPOSITION.md §III.3 breaker semantics, the future
9442/// `feira lint` per-`:politicas` breaker-window bound-check against
9443/// [`crate::POLICY_BREAKER_WINDOW_MAX`] and
9444/// [`crate::POLICY_BREAKER_MAX_FAILURES_MAX`]). Peer of
9445/// [`POLITICAS_KEY_TIMEOUT`] on the same
9446/// [`crate::aplicacao::MeshPolicy`] singleton serialized-key axis; see
9447/// [`POLITICAS_KEY_TIMEOUT`] for the full lift rationale.
9448///
9449/// This axis is one of the three non-trivial camelCase transforms
9450/// [`crate::aplicacao::MeshPolicy`]'s derive emits (`circuit_breaker`
9451/// → `circuitBreaker`, `mtls_required` → `mtlsRequired`, `rate_limit`
9452/// → `rateLimit`); a future accidental `rename_all = "snake_case"` /
9453/// `"kebab-case"` / verbatim-field-name flip at the derive would
9454/// silently rebrand the emitted key to `circuit_breaker` /
9455/// `circuit-breaker` / `circuit_breaker` respectively, breaking every
9456/// downstream `Value::get(POLITICAS_KEY_CIRCUIT_BREAKER)` consumer.
9457/// The identity pin (`mesh_policy_serde_keys_match_lifted_politicas_key_consts`
9458/// on the source-side type) catches drift on all three non-trivial
9459/// axes simultaneously.
9460pub const POLITICAS_KEY_CIRCUIT_BREAKER: &str = "circuitBreaker";
9461
9462/// Canonical camelCase JSON/YAML top-level key for the
9463/// [`crate::aplicacao::MeshPolicy`] struct's `mtls_required`
9464/// mTLS-enforcement-toggle axis — the `mtlsRequired:` field the M3
9465/// Aplicacao's `#[serde(rename_all = "camelCase")]` derive on
9466/// [`crate::aplicacao::MeshPolicy`] emits at the singleton `:politicas`
9467/// block, and the exact camelCase scalar (Rust field `mtls_required`
9468/// → serde-emitted `mtlsRequired`) every downstream mesh-identity
9469/// consumer must probe on (the future M4 per-edge `:politicas` overlay
9470/// projection onto Cilium `CiliumNetworkPolicy` per-rule
9471/// [`CILIUM_KEY_AUTHENTICATION`] mode dispatch under the
9472/// [`cilium_auth_mode`] bijection projection (a4dc43c) — the mesh's
9473/// sandboxing-by-default posture MESH-COMPOSITION.md §III.3 promises
9474/// keys off this exact byte-sequence to opt out of mTLS enforcement
9475/// per-edge, so drift here silently reopens the every-edge-mTLS
9476/// invariant the substrate defaults to). Peer of
9477/// [`POLITICAS_KEY_TIMEOUT`] on the same
9478/// [`crate::aplicacao::MeshPolicy`] singleton serialized-key axis; see
9479/// [`POLITICAS_KEY_TIMEOUT`] for the full lift rationale.
9480pub const POLITICAS_KEY_MTLS_REQUIRED: &str = "mtlsRequired";
9481
9482/// Canonical camelCase JSON/YAML top-level key for the
9483/// [`crate::aplicacao::MeshPolicy`] struct's `rate_limit`
9484/// token-bucket-rate-limit axis — the `rateLimit:` field the M3
9485/// Aplicacao's `#[serde(rename_all = "camelCase")]` derive on
9486/// [`crate::aplicacao::MeshPolicy`] emits at the singleton `:politicas`
9487/// block, and the exact camelCase scalar (Rust field `rate_limit` →
9488/// serde-emitted `rateLimit`) every downstream rate-limit consumer
9489/// must probe on (the future M4 per-edge `:politicas` overlay
9490/// projection onto the mesh's per-backend token-bucket `(rate,
9491/// window)` decoder driven by the canonical
9492/// [`crate::aplicacao::rate_limit_codec`] unit-suffix bijection). Peer
9493/// of [`POLITICAS_KEY_TIMEOUT`] on the same
9494/// [`crate::aplicacao::MeshPolicy`] singleton serialized-key axis; see
9495/// [`POLITICAS_KEY_TIMEOUT`] for the full lift rationale.
9496pub const POLITICAS_KEY_RATE_LIMIT: &str = "rateLimit";
9497
9498/// Canonical camelCase JSON/YAML sub-key for the
9499/// [`crate::aplicacao::CircuitBreaker`] struct's `max_failures`
9500/// consecutive-failure-count axis — the `maxFailures:` field the M3
9501/// Aplicacao's `#[serde(rename_all = "camelCase")]` derive on
9502/// [`crate::aplicacao::CircuitBreaker`] emits inside the
9503/// [`POLITICAS_KEY_CIRCUIT_BREAKER`] sub-block, and the exact camelCase
9504/// scalar (Rust field `max_failures` → serde-emitted `maxFailures`,
9505/// the load-bearing non-trivial camelCase transform on this
9506/// [`CircuitBreaker`][cb] axis alongside the no-op
9507/// [`CIRCUIT_BREAKER_KEY_WINDOW`] sibling) every downstream breaker-
9508/// tuning consumer must probe on (the future M4 per-edge `:politicas`
9509/// overlay projection onto the mesh's per-backend
9510/// consecutive-failure-counter tripping threshold per
9511/// MESH-COMPOSITION.md §III.3 breaker semantics, the future
9512/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission-time
9513/// breaker cross-check against
9514/// [`crate::POLICY_BREAKER_MAX_FAILURES_MAX`], the future
9515/// `feira lint` per-`:politicas :circuit-breaker` bound-check gate).
9516///
9517/// [cb]: crate::aplicacao::CircuitBreaker
9518///
9519/// Peer of [`CIRCUIT_BREAKER_KEY_WINDOW`] on the same
9520/// [`crate::aplicacao::CircuitBreaker`] serialized-key axis; the two
9521/// consts together close the sub-block's typed-struct axis. Extends
9522/// the [`POLITICAS_KEY_CIRCUIT_BREAKER`] parent-axis lift (b55cca7)
9523/// one level deeper — the parent const names the outer sub-block key
9524/// the derive on [`crate::aplicacao::MeshPolicy`] emits, this pair
9525/// names the inner keys the derive on the payload type emits, so a
9526/// consumer walking `Value::get(POLITICAS_KEY_CIRCUIT_BREAKER)
9527/// .and_then(|v| v.get(CIRCUIT_BREAKER_KEY_MAX_FAILURES))` navigates
9528/// the whole [`crate::aplicacao::MeshPolicy`] breaker-tuning shape
9529/// entirely through lifted canonical byte-sequences with no inline
9530/// string literal at either level.
9531///
9532/// A future accidental `rename_all = "snake_case"` /
9533/// `"kebab-case"` / verbatim-field-name flip at the derive on
9534/// [`crate::aplicacao::CircuitBreaker`] would silently rebrand the
9535/// emitted key to `max_failures` / `max-failures` / `max_failures`
9536/// respectively, breaking every downstream
9537/// `Value::get(CIRCUIT_BREAKER_KEY_MAX_FAILURES)` consumer — with the
9538/// drift surfacing at apply time far from the derive-attr commit. The
9539/// identity pin
9540/// (`circuit_breaker_serde_keys_match_lifted_circuit_breaker_key_consts`
9541/// on the source-side type) catches drift at caixa-core build time.
9542///
9543/// Same discipline every peer camelCase serde-key lift carries
9544/// ([`M2_LIMITS_KEY_MEMORY`] etc. (d8b8b4f),
9545/// [`M2_BEHAVIOR_KEY_ON_INIT`] etc. (21fe462),
9546/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
9547/// (36ffe65), [`SUPERVISOR_KEY_ESTRATEGIA`] etc. (40cc4e5),
9548/// [`POLITICAS_KEY_TIMEOUT`] etc. (b55cca7)).
9549pub const CIRCUIT_BREAKER_KEY_MAX_FAILURES: &str = "maxFailures";
9550
9551/// Canonical camelCase JSON/YAML sub-key for the
9552/// [`crate::aplicacao::CircuitBreaker`] struct's `window`
9553/// failure-counter reset-window axis — the `window:` field the M3
9554/// Aplicacao's `#[serde(rename_all = "camelCase")]` derive on
9555/// [`crate::aplicacao::CircuitBreaker`] emits inside the
9556/// [`POLITICAS_KEY_CIRCUIT_BREAKER`] sub-block. The Rust field is
9557/// lowercase `window`; `#[serde(rename_all = "camelCase")]` is a
9558/// no-op on this axis and the emitted key equals the source-side
9559/// field name byte-for-byte. Peer of
9560/// [`CIRCUIT_BREAKER_KEY_MAX_FAILURES`] on the same
9561/// [`crate::aplicacao::CircuitBreaker`] serialized-key axis; see
9562/// [`CIRCUIT_BREAKER_KEY_MAX_FAILURES`] for the full lift rationale.
9563pub const CIRCUIT_BREAKER_KEY_WINDOW: &str = "window";
9564
9565/// Canonical `lareira-fleet-programs` values-schema key naming the
9566/// per-caixa entry sequence — the exact YAML key the fleet-programs
9567/// library chart's `values.yaml` reads as `programs:` (a sequence of
9568/// per-Servico entries the chart's `range` iterates over to emit one
9569/// `ComputeUnit` CR per entry). Two production consumers in
9570/// [`caixa_flux`] carry this key on the same fleet-programs schema
9571/// axis:
9572///
9573/// 1. [`caixa_flux::upsert_into_helmrelease_programs`] — the writer-
9574///    side upsert path on the aggregator-HelmRelease shape. Walks
9575///    `HelmRelease.spec.values.programs[]` under this exact key to
9576///    match by `metadata.name` and either replace-in-place or append.
9577///
9578/// 2. [`caixa_flux::upsert_into_programs_yaml`] — the writer-side
9579///    upsert path on the bare-values.yaml shape. Walks the
9580///    top-level `programs[]` sequence under the same key.
9581///
9582/// Until this lift landed both consumers carried the bare `"programs"`
9583/// byte inline — `upsert_into_helmrelease_programs`'s
9584/// `values_map.entry(Value::String("programs".into()))` at
9585/// `caixa-flux/src/lib.rs:539` and `upsert_into_programs_yaml`'s
9586/// `let programs_key = Value::String("programs".into());` at
9587/// `caixa-flux/src/lib.rs:591`. A future fleet-programs schema-key
9588/// rebrand (the library chart moving to plural `programas` for
9589/// Brazilian-Portuguese uniformity with the rest of the substrate's
9590/// surface, to a namespaced `pleme.pleme.io/programs` for multi-tenant
9591/// aggregator-values isolation, or to per-kind `servicos` / `aplicacaos`
9592/// splits once the schema grows past the flat sequence — the
9593/// ABSORPTION-ROADMAP.md M4 trajectory) without a coordinated edit
9594/// on both writer-side sites would silently emit an entry under one
9595/// key (e.g. `programas:`) while the peer-side upsert still probes
9596/// the prior key — the aggregator's `range .Values.programs` would
9597/// then iterate an empty sequence and every `ComputeUnit` CR would
9598/// silently vanish from the cluster's fleet, with the failure
9599/// surfacing as "the newly-deployed Servico's pods never spin up" far
9600/// from the rebrand commit's source. Lifting the literal to one
9601/// `&'static str` closes the drift footgun structurally — both
9602/// consumers read from the same memory, so any future rebrand reaches
9603/// both writer sites by construction and a CI build that re-introduces
9604/// a sibling inline `"programs"` literal trips the peer pinning tests
9605/// at the build-time fail-before-deploy posture every prior
9606/// load-bearing-string lift on this surface
9607/// ([`M3_KEY_PLACEMENT`] under the same `programs.yaml` per-entry
9608/// axis, [`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`]
9609/// on the peer M2 overlay-key surfaces, [`DEFAULT_NAMESPACE`]
9610/// / [`DEFAULT_LIBRARY_NAME`] / [`DEFAULT_SERVICO_PORT`] on the peer
9611/// shared-string / port surfaces) establishes.
9612///
9613/// Peer of [`M3_KEY_PLACEMENT`] on the same fleet-programs values
9614/// schema — that constant names the per-entry overlay key, this one
9615/// names the top-level array key both writer verbs upsert into.
9616pub const FLEET_PROGRAMS_KEY_PROGRAMS: &str = "programs";
9617
9618/// Canonical `lareira-fleet-programs` values-schema key naming the
9619/// per-entry name discriminator — the `name:` field the library
9620/// chart's `range .Values.programs` step reads to key each rendered
9621/// `ComputeUnit` CR's `metadata.name` off, and the exact key both
9622/// writer-side upsert paths in [`caixa_flux`] match against to
9623/// replace-in-place-vs-append. Peer of [`FLEET_PROGRAMS_KEY_PROGRAMS`]
9624/// on the same fleet-programs values schema — that constant names
9625/// the top-level array key, this one names the per-entry name-axis
9626/// both writer verbs walk the array by.
9627///
9628/// Two production consumers write this key:
9629///
9630/// 1. [`caixa_flux::programs_yaml_entry`] — the emit-side per-Servico
9631///    entry-builder writes the per-entry name-axis at this exact key
9632///    (seeded from the Caixa's `nome`), at
9633///    `caixa-flux/src/lib.rs`'s `entry.insert("name".into(), …)` call.
9634/// 2. [`caixa_mesh::programs_for_aplicacao`] — the Aplicacao-side
9635///    per-`:membros` entry-builder writes the peer per-entry name-axis
9636///    at the same key (seeded from each `:membros` entry's `:caixa`
9637///    binding), at `caixa-mesh/src/lib.rs`'s per-member
9638///    `entry.insert("name".into(), …)` call.
9639///
9640/// Two production consumers read this key:
9641///
9642/// 3. [`caixa_flux::upsert_into_helmrelease_programs`] — the writer-
9643///    side upsert path on the aggregator-HelmRelease shape reads the
9644///    per-entry key twice (new-entry's `.get("name")` extract +
9645///    per-slot `.get("name")` match-vs-new_name inside
9646///    `HelmRelease.spec.values.programs[]`), plus a
9647///    `Error::MissingField("name")` diagnostic naming the same axis.
9648/// 4. [`caixa_flux::upsert_into_programs_yaml`] — the writer-side
9649///    upsert path on the bare-values.yaml shape reads the same per-
9650///    entry key over the top-level `programs[]` sequence via the
9651///    same three-site (extract + match + `MissingField`) shape.
9652///
9653/// Until this lift landed both writers carried the bare `"name"`
9654/// byte inline at every read + `Error::MissingField("name")`
9655/// diagnostic site, and both emitters carried the same bare byte at
9656/// their `entry.insert("name".into(), …)` call. A future fleet-
9657/// programs schema-key rebrand on the per-entry name-discriminator
9658/// axis (per the same trajectory [`FLEET_PROGRAMS_KEY_PROGRAMS`]'s
9659/// doc-comment names — the `lareira-fleet-programs` library chart
9660/// moving its per-entry name-axis to `nome:` for Brazilian-Portuguese
9661/// uniformity with the rest of the substrate's surface, or to a
9662/// namespaced `pleme.pleme.io/name` for multi-tenant aggregator
9663/// values isolation, or to per-kind `servico-name` / `aplicacao-name`
9664/// splits once the schema grows past the flat sequence — the
9665/// ABSORPTION-ROADMAP.md M4 trajectory) without a coordinated edit
9666/// across all four sites would silently split the schema: one
9667/// emitter would write under `nome:` while the peer-side upsert
9668/// still probed `name:` — the aggregator's `range .Values.programs`
9669/// would then iterate entries whose per-entry name-axis the library
9670/// chart's `metadata.name` templating reads as empty (or match
9671/// against the wrong entry on upsert), and every rendered
9672/// `ComputeUnit` CR would silently collide on empty
9673/// `metadata.name` or vanish at the aggregator's per-entry name-
9674/// keyed reduce step, with the failure surfacing as "the Servico's
9675/// pods never spin up under the expected name" far from the rebrand
9676/// commit's source. Lifting the literal to one `&'static str` closes
9677/// the drift footgun structurally — every consumer reads the same
9678/// memory, so any future rebrand reaches all four sites by
9679/// construction and a CI build that re-introduces a sibling inline
9680/// `"name"` literal trips the peer pinning tests at the build-time
9681/// fail-before-deploy posture every prior load-bearing-string lift
9682/// on this surface ([`FLEET_PROGRAMS_KEY_PROGRAMS`] on the sibling
9683/// fleet-programs top-level array-key axis, [`M3_KEY_PLACEMENT`] /
9684/// [`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`]
9685/// on the peer per-entry overlay-key surfaces) establishes.
9686///
9687/// Byte-identical to [`KUBE_KEY_NAME`] today — both resolve to the
9688/// same three-byte `"name"` literal — but semantically distinct:
9689/// [`KUBE_KEY_NAME`] names the K8s CR canonical `metadata.name` axis
9690/// (every rendered CR's identity discriminator, spelled per the K8s
9691/// apiserver's OpenAPI v3 schema), while this constant names the
9692/// `lareira-fleet-programs` library chart's per-entry name-axis
9693/// (spelled per the chart's `values.schema.json` — a separate schema
9694/// contract). Splitting the two lets each schema's future rebrand
9695/// land independently at its canonical const definition without
9696/// coupling the K8s CR canonical-key axis to the fleet-programs
9697/// values-schema axis (or vice versa).
9698pub const FLEET_PROGRAMS_KEY_NAME: &str = "name";
9699
9700/// Canonical `lareira-fleet-programs` values-schema key naming the
9701/// per-entry parent-Aplicacao-graph discriminator — the `aplicacao:`
9702/// annotation the substrate operator's fleet-aggregator reads to
9703/// group each rendered `programs[]` entry back onto the parent
9704/// Aplicacao its M3 `:membros` list contributed it, and the exact
9705/// key downstream fleet consumers (per-graph observability filters,
9706/// per-Aplicacao Cilium-policy reconciliation, per-graph Gateway/
9707/// `HTTPRoute` attachment) walk to project the flat `programs[]`
9708/// sequence back onto its typed Aplicacao graph.
9709///
9710/// Peer of [`FLEET_PROGRAMS_KEY_NAME`] and [`M3_KEY_PLACEMENT`] on
9711/// the same fleet-programs values schema — `FLEET_PROGRAMS_KEY_NAME`
9712/// carries the per-entry Servico-name discriminator (the `:membros`
9713/// row's own `:caixa` binding), `M3_KEY_PLACEMENT` carries the M3
9714/// placement overlay cloned per entry, and this constant carries the
9715/// per-entry parent-Aplicacao-nome annotation the aggregator uses to
9716/// group entries back into their Aplicacao graph. Together the three
9717/// per-entry keys (plus the top-level [`FLEET_PROGRAMS_KEY_PROGRAMS`]
9718/// array key) name every axis one `programs[]` entry the caixa-mesh
9719/// fan-out emits contributes to the substrate operator's read shape.
9720///
9721/// One production consumer writes this key:
9722/// [`caixa_mesh::programs_for_aplicacao`] — the Aplicacao-side
9723/// per-`:membros` entry-builder writes the parent-Aplicacao-nome
9724/// annotation at this exact key (seeded from the enclosing Caixa's
9725/// `:nome`), at `caixa-mesh/src/lib.rs`'s per-member
9726/// `entry.insert("aplicacao".into(), …)` call. Unlike the peer
9727/// [`FLEET_PROGRAMS_KEY_NAME`] axis (written by both caixa-flux's
9728/// per-Servico entry builder and caixa-mesh's per-`:membros` builder
9729/// — a Servico rendered standalone has no parent-Aplicacao annotation
9730/// to carry), the parent-Aplicacao-nome annotation is emitted only
9731/// by the caixa-mesh Aplicacao-side fan-out — Servicos rendered
9732/// standalone through the caixa-flux path leave the annotation
9733/// absent, which is exactly the discriminator the operator's
9734/// aggregator uses to distinguish Aplicacao-graph-scoped entries
9735/// from stand-alone Servico entries.
9736///
9737/// Until this lift landed the caixa-mesh emitter carried the bare
9738/// `"aplicacao"` byte inline at its `entry.insert("aplicacao".into(),
9739/// …)` call, and the peer in-file test probe (the
9740/// `programs_for_aplicacao_annotates_with_parent_nome` fixture's
9741/// `e.get("aplicacao").and_then(|v| v.as_str())` navigation) carried
9742/// the same bare byte at its readback site. A future fleet-programs
9743/// schema-key rebrand on the per-entry parent-Aplicacao-annotation
9744/// axis (per the same trajectory the sibling [`FLEET_PROGRAMS_KEY_NAME`]
9745/// doc-comment names — the `lareira-fleet-programs` library chart
9746/// moving its per-entry parent-graph-annotation to a namespaced
9747/// `pleme.pleme.io/aplicacao` for multi-tenant aggregator isolation
9748/// once the M4 flat-`programs[]`-per-cluster shape splits into
9749/// per-graph sequences, or to `graph:` for parity with the M3
9750/// `:contratos` graph nomenclature, or to typed `parent:` on the
9751/// ABSORPTION-ROADMAP.md M4 hierarchical-fleet trajectory) without
9752/// a coordinated edit across both sites would silently split the
9753/// schema: the emitter would write under the drifted key while the
9754/// aggregator's per-Aplicacao filter would still read `aplicacao:`
9755/// — every fan-out entry would silently vanish from its parent
9756/// graph's projected view at the aggregator's per-Aplicacao reduce
9757/// step, with the failure surfacing as "the Aplicacao's Servicos
9758/// never appear in per-graph observability filters" far from the
9759/// rebrand commit's source. Lifting the literal to one `&'static
9760/// str` closes the drift footgun structurally — every consumer
9761/// reads the same memory, so any future rebrand reaches both sites
9762/// by construction and a CI build that re-introduces a sibling
9763/// inline `"aplicacao"` literal trips the peer pinning tests at the
9764/// build-time fail-before-deploy posture every prior load-bearing-
9765/// string lift on this surface ([`FLEET_PROGRAMS_KEY_PROGRAMS`] on
9766/// the sibling fleet-programs top-level array-key axis,
9767/// [`FLEET_PROGRAMS_KEY_NAME`] on the peer per-entry name-
9768/// discriminator axis, [`M3_KEY_PLACEMENT`] / [`M2_KEY_LIMITS`] /
9769/// [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`] on the peer per-
9770/// entry overlay-key surfaces) establishes.
9771///
9772/// Byte-identical to the string form of the
9773/// [`caixa_core::CaixaKind::Aplicacao`] enum variant today — both
9774/// resolve to the same nine-byte `"aplicacao"` literal — but
9775/// semantically distinct: `CaixaKind`'s `Aplicacao` variant names
9776/// the `:kind` enum arm (the typed kind-tag every `defcaixa` selects
9777/// among), while this constant names the `lareira-fleet-programs`
9778/// library chart's per-entry parent-graph-annotation axis (spelled
9779/// per the chart's `values.schema.json` — a separate schema
9780/// contract, one whose future rebrand can land independently of the
9781/// kind-tag axis). Splitting the two lets each schema's future
9782/// rebrand land at its canonical const/variant definition without
9783/// coupling the `:kind` enum-tag axis to the fleet-programs values-
9784/// schema axis (or vice versa) — the same discipline the sibling
9785/// [`FLEET_PROGRAMS_KEY_NAME`] doc-comment establishes vs.
9786/// [`KUBE_KEY_NAME`] on the K8s CR canonical name-axis.
9787pub const FLEET_PROGRAMS_KEY_APLICACAO: &str = "aplicacao";
9788
9789/// Canonical `lareira-fleet-programs` values-schema key naming the
9790/// per-entry version-constraint discriminator — the `versao:` field
9791/// each rendered `programs[]` entry carries so the substrate operator's
9792/// per-`:membros` resolver can resolve each member's caixa.lisp against
9793/// its Aplicacao-declared version-constraint. Every `:membros` row's
9794/// `:versao` (the semver / range constraint the M3 Aplicacao names on
9795/// its `:membros` list) flows through this exact key on the emitted
9796/// per-entry programs.yaml row.
9797///
9798/// Peer of [`FLEET_PROGRAMS_KEY_NAME`], [`FLEET_PROGRAMS_KEY_APLICACAO`],
9799/// and [`M3_KEY_PLACEMENT`] on the same fleet-programs values schema —
9800/// `FLEET_PROGRAMS_KEY_NAME` carries the per-entry Servico-name
9801/// discriminator (each `:membros` row's `:caixa` binding),
9802/// `FLEET_PROGRAMS_KEY_APLICACAO` carries the per-entry parent-graph
9803/// annotation, `M3_KEY_PLACEMENT` carries the M3 placement overlay
9804/// cloned per entry, and this constant carries the per-entry version-
9805/// constraint the operator's resolver reads to fetch the correct
9806/// caixa.lisp release. Together the four per-entry keys (plus the
9807/// top-level [`FLEET_PROGRAMS_KEY_PROGRAMS`] array key) name every axis
9808/// one `programs[]` entry the caixa-mesh fan-out emits contributes to
9809/// the substrate operator's read shape.
9810///
9811/// One production consumer writes this key:
9812/// [`caixa_mesh::programs_for_aplicacao`] — the Aplicacao-side
9813/// per-`:membros` entry-builder writes the per-entry version-
9814/// constraint at this exact key (seeded from each `:membros` row's
9815/// `:versao` binding), at `caixa-mesh/src/lib.rs`'s per-member
9816/// `entry.insert("versao".into(), …)` call. Unlike the peer
9817/// [`FLEET_PROGRAMS_KEY_NAME`] axis (written by both caixa-flux's
9818/// per-Servico entry builder and caixa-mesh's per-`:membros` builder
9819/// — a Servico rendered standalone through the caixa-flux path resolves
9820/// its own `:versao` from its `caixa.lisp` root and hands it to the
9821/// resolver via a distinct path), the per-`:membros` version-constraint
9822/// annotation is emitted only by the caixa-mesh Aplicacao-side fan-out.
9823///
9824/// Until this lift landed the caixa-mesh emitter carried the bare
9825/// `"versao"` byte inline at its `entry.insert("versao".into(), …)`
9826/// call — a partial single-source where three of four per-entry
9827/// fleet-programs axis keys were canonical
9828/// ([`FLEET_PROGRAMS_KEY_NAME`] via 030a63f,
9829/// [`FLEET_PROGRAMS_KEY_APLICACAO`] via cc69ac2, [`M3_KEY_PLACEMENT`])
9830/// and the fourth was scattered. Lifting the fourth key completes the
9831/// fleet-programs values-schema single-sourcing across every per-entry
9832/// axis; every future per-graph aggregator, per-`:membros` resolver,
9833/// per-entry version-constraint consumer inherits the same `&'static
9834/// str` by construction. A future schema-key rebrand on the per-entry
9835/// version-constraint axis (a namespaced `pleme.pleme.io/versao` for
9836/// multi-tenant aggregator isolation, or `version:` for parity with
9837/// upstream conventions, or typed `constraint:` on the ABSORPTION-
9838/// ROADMAP.md M4 typed-resolver trajectory) lands at the one const
9839/// rather than scattered across every future per-emitter/per-resolver
9840/// site.
9841///
9842/// Byte-identical to the `Membro::versao` field name on the M3
9843/// [`AplicacaoSpec`](aplicacao::AplicacaoSpec) today — both resolve to the same six-byte `"versao"`
9844/// literal — but semantically distinct: `Membro::versao` names the
9845/// author-side `:versao` slot on each `:membros` row (the typed
9846/// version-constraint slot every `defcaixa` populates on its
9847/// `:membros` list), while this constant names the
9848/// `lareira-fleet-programs` library chart's per-entry version-
9849/// constraint axis (spelled per the chart's `values.schema.json` — a
9850/// separate schema contract, one whose future rebrand can land
9851/// independently of the author-side slot-name axis). Splitting the two
9852/// lets each schema's future rebrand land at its canonical const /
9853/// field definition without coupling the author-side slot-name axis to
9854/// the fleet-programs values-schema axis (or vice versa) — the same
9855/// discipline the sibling [`FLEET_PROGRAMS_KEY_APLICACAO`] doc-comment
9856/// establishes vs. the [`CaixaKind::Aplicacao`] enum-variant tag.
9857pub const FLEET_PROGRAMS_KEY_VERSAO: &str = "versao";
9858
9859/// Canonical pleme-io label namespace prefix. Every cluster object
9860/// emitted by any caixa-side renderer that needs to carry the
9861/// pleme-io workload identity uses this prefix; runtime label
9862/// injectors (`lareira-fleet-programs` chart's pod template,
9863/// `pleme-computeunit` library chart's identity sidecar, the
9864/// caixa-operator's pod-mutating webhook) and runtime label
9865/// consumers (Cilium identity-based policy, Hubble flow attribution,
9866/// `caixa-mesh`'s policy / Gateway emission, future
9867/// observability/tracing renderers) all spell the same prefix
9868/// exactly the same way — drift between *any* of those = a
9869/// CiliumNetworkPolicy that matches no pods, a Hubble flow that
9870/// can't be correlated to its workload, an OpenTelemetry resource
9871/// attribute that doesn't join to its caixa lacre.
9872///
9873/// Lifted to a const so a future top-level rebrand or multi-tenant
9874/// label-namespace migration is a one-line edit, not a search-and-
9875/// replace across every renderer crate.
9876pub const PLEME_LABEL_PREFIX: &str = "pleme.pleme.io";
9877
9878/// Canonical pleme-io label key naming the **Aplicacao** the workload
9879/// belongs to. Together with [`LABEL_PROGRAM`] this is the load-bearing
9880/// identity tuple every per-Aplicacao mesh renderer (Cilium, Gateway,
9881/// future caixa-otel) keys off — `(LABEL_APLICACAO, LABEL_PROGRAM)` =
9882/// the unique workload selector inside one cluster.
9883pub const LABEL_APLICACAO: &str = "pleme.pleme.io/aplicacao";
9884
9885/// Canonical pleme-io label key naming the **program** (i.e. the
9886/// caixa Servico's `:nome`) a pod runs. `LABEL_APLICACAO` +
9887/// `LABEL_PROGRAM` together pick exactly one workload identity in one
9888/// cluster. Used as the `matchLabels` axis on every Cilium
9889/// `endpointSelector` / `fromEndpoints` rule and on Gateway API
9890/// `backendRefs` selectors emitted by [`crate`]'s downstream
9891/// renderers.
9892pub const LABEL_PROGRAM: &str = "pleme.pleme.io/program";
9893
9894/// Canonical pleme-io label key naming the **contrato** (the M3
9895/// `:contratos` edge: `<de>-to-<para>`) a CiliumNetworkPolicy enforces.
9896/// Carried on the policy's *own* labels (not on workload pods) so
9897/// Hubble + cluster operators can group flows by typed contrato edge,
9898/// not just by source/destination pod identity.
9899pub const LABEL_CONTRATO: &str = "pleme.pleme.io/contrato";
9900
9901/// Canonical M3 `:contratos` edge-direction separator byte-string every
9902/// caixa-mesh emitter that encodes a typed edge as a K8s-name-shaped
9903/// scalar (the [`LABEL_CONTRATO`] label value carried on every
9904/// per-`(:de, :para)` `CiliumNetworkPolicy`'s `metadata.labels`, and
9905/// the per-`(:de, :para)` `CiliumNetworkPolicy`'s `metadata.name`
9906/// itself) inserts between the `:de` and `:para` halves of the typed
9907/// edge tuple. Load-bearing on both the writer half (the CNP renderer)
9908/// and the reader half (Hubble flow grouping by contrato label,
9909/// per-CNP operator filters, `kubectl get cnp -l pleme.pleme.io/contrato=<de>-to-<para>`
9910/// grep-by-label). Until this lift landed the `-to-` byte-string sat
9911/// in two verbatim inline-`format!` sites at the caixa-mesh
9912/// `cilium_network_policies` emitter — one at the
9913/// [`LABEL_CONTRATO`] `labels.insert(...)` call and one at the
9914/// [`kube_resource_skeleton`] `name:` argument — with no compile-time
9915/// link between them. A future edge-encoding rebrand (`-to-` → `->`
9916/// for compactness, `-to-` → `_to_` to reserve `-` for embedded
9917/// DNS-1123-label boundaries, an edge-direction-arrow migration to
9918/// UTF-8 shapes) would have had to be threaded through both sites in
9919/// lockstep or the two would silently split: one CNP's `metadata.name`
9920/// keys off the drifted encoding, its own `metadata.labels.pleme.pleme.io/contrato`
9921/// value keys off the original, and every operator-side grep-by-label
9922/// query (`kubectl get cnp -l pleme.pleme.io/contrato=cart-to-catalog`)
9923/// finds the label but the resulting CNP's `metadata.name` no longer
9924/// matches the queried edge encoding. Every downstream consumer that
9925/// joins the two axes (the M4 mesh-graph audit, the future Hubble-side
9926/// contrato-flow renderer, the operator's per-edge policy inspector)
9927/// silently loses the join. Lifted onto one `&'static str` so a future
9928/// edge-encoding rebrand lands at one const, and every downstream
9929/// consumer picks up the new encoding by construction.
9930pub const CONTRATO_EDGE_LABEL_SEPARATOR: &str = "-to-";
9931
9932/// Canonical M3 `:contratos` edge label value — the `<de>-to-<para>`
9933/// K8s-name-shaped scalar every per-`(:de, :para)` `CiliumNetworkPolicy`
9934/// document carries at its `metadata.labels.pleme.pleme.io/contrato`
9935/// axis (the [`LABEL_CONTRATO`] label key). Composes on the lifted
9936/// [`CONTRATO_EDGE_LABEL_SEPARATOR`] byte-string so a future
9937/// edge-encoding rebrand lands at one canonical composition, and every
9938/// downstream consumer that grep-by-label picks up the new encoding by
9939/// construction.
9940///
9941/// Peer of [`cilium_network_policy_name`] on the sibling per-`(:de,
9942/// :para)` CNP `metadata.name` encoding axis — the CNP name composes
9943/// on this helper's output (the CNP `metadata.name` is
9944/// `format!("{aplicacao}-{contrato_edge_label(de, para)}")`), so a
9945/// future rebrand on either axis reaches both consumers through one
9946/// canonical composition instead of a coordinated two-site rewrite of
9947/// caixa-mesh's `cilium_network_policies` per-`(:de, :para)` group's
9948/// [`LABEL_CONTRATO`] `labels.insert(...)` call and the
9949/// [`kube_resource_skeleton`] `name:` argument.
9950#[must_use]
9951pub fn contrato_edge_label(de: &str, para: &str) -> String {
9952    format!("{de}{CONTRATO_EDGE_LABEL_SEPARATOR}{para}")
9953}
9954
9955/// Canonical per-`(:de, :para)` `CiliumNetworkPolicy` `metadata.name`
9956/// K8s-name-shaped scalar every caixa-mesh `cilium_network_policies`
9957/// emitter mounts its per-edge CNP under. Composes on the lifted
9958/// [`contrato_edge_label`] helper (the CNP name is the parent
9959/// Aplicacao's `:nome` joined to the contrato-edge-label by a
9960/// canonical `-` separator: `format!("{aplicacao}-{edge}")`), so the
9961/// two axes — the CNP `metadata.labels.pleme.pleme.io/contrato` value
9962/// and the CNP `metadata.name` — share one canonical
9963/// edge-encoding source of truth ([`CONTRATO_EDGE_LABEL_SEPARATOR`]).
9964///
9965/// Peer of [`contrato_edge_label`] on the parent-composition axis —
9966/// the two writer-side helpers close the canonical
9967/// `(LABEL_CONTRATO-value, metadata.name)` per-CNP identity pair so a
9968/// future edge-encoding rebrand or a per-emitter typo can't silently
9969/// split the two axes at emit time and orphan every operator-side
9970/// grep-by-label query at apply time far from the source caixa.lisp.
9971///
9972/// The `aplicacao` prefix scopes the emitted CNP to its owning
9973/// Aplicacao (so two Aplicacaos hosting a same-named `(de, para)`
9974/// contrato edge — `checkout-cart-to-catalog` vs
9975/// `orders-cart-to-catalog` — land at distinct CNP `metadata.name`s
9976/// with no `kubectl apply` collision at the shared namespace).
9977#[must_use]
9978pub fn cilium_network_policy_name(aplicacao: &str, de: &str, para: &str) -> String {
9979    let edge = contrato_edge_label(de, para);
9980    format!("{aplicacao}-{edge}")
9981}
9982
9983/// Canonical per-`:entrada` `HTTPRoute` `metadata.name` K8s-name-shaped
9984/// scalar every caixa-mesh `gateway_routes` emitter mounts its
9985/// per-`:entrada` HTTPRoute under. Composes the parent Aplicacao's
9986/// `:nome` and the `:entrada :para` destination Servico's `:nome` on a
9987/// canonical `-` separator (`format!("{aplicacao}-{para}")`), so the
9988/// per-`(:aplicacao, :entrada.para)` HTTPRoute identity axis lives at
9989/// one composer instead of a verbatim inline `format!("{}-{}",
9990/// caixa.nome, entrada.para)` at the [`caixa_mesh::gateway_routes`]
9991/// [`kube_resource_skeleton`] `name:` argument.
9992///
9993/// Peer of [`cilium_network_policy_name`] on the sibling per-Aplicacao
9994/// per-CR K8s-name-shaped-identity-scalar axis: the CNP name composer
9995/// carries the per-`(:de, :para)` L4/L7 policy CR name and this
9996/// composer carries the per-`:entrada` L7 route CR name; both share
9997/// the same "aplicacao-prefixed sub-identity" discipline (a per-CR
9998/// identity scalar keyed off the parent Aplicacao's `:nome` joined to
9999/// the per-CR sub-axis by a canonical `-` separator) so a future
10000/// substrate-side per-Aplicacao Gateway API axis extension
10001/// (`GRPCRoute` on grpc-shaped `:contratos` payloads once the sibling
10002/// [`WitTarget`] variant lands, `TCPRoute` on the sibling l4-only
10003/// tcp-shaped payload axis, per-`:entrada` `HTTPRouteFilter` /
10004/// `BackendTLSPolicy` overlays the Gateway API v1.x per-route policy
10005/// extension surface acknowledges) reaches the shared "aplicacao-prefix
10006/// + sub-axis + canonical `-` separator" naming discipline through
10007/// this composer's peer-shape by construction. Until this lift landed
10008/// the HTTPRoute `metadata.name` axis sat as a verbatim inline
10009/// `format!("{}-{}", caixa.nome, entrada.para)` at the
10010/// [`caixa_mesh::gateway_routes`] emitter (with an in-file test-side
10011/// probe pinning the expected `checkout-cart` shape by verbatim
10012/// literal), and any future name-encoding rebrand on this axis
10013/// (`<aplicacao>-<para>` → `<aplicacao>-httproute-<para>` for
10014/// operator-side per-CR-kind disambiguation once the sibling
10015/// GRPCRoute / TCPRoute lands and their names would otherwise collide,
10016/// `<aplicacao>-<para>` → `<aplicacao>.<para>` on a DNS-1123-subdomain-
10017/// safe axis migration, a per-namespace scoping prefix for
10018/// multi-tenant Aplicacao hosting) would have had to be threaded
10019/// through both sites in lockstep or the HTTPRoute `metadata.name`
10020/// silently split from the operator-side grep-by-name / `kubectl get
10021/// httproute -n tatara-system <aplicacao>-<para>` lookup encoding at
10022/// apply time far from the source caixa.lisp.
10023///
10024/// The `aplicacao` prefix scopes the emitted HTTPRoute to its owning
10025/// Aplicacao (so two Aplicacaos hosting a same-named `:entrada :para`
10026/// destination — `checkout-cart` vs `orders-cart` — land at distinct
10027/// HTTPRoute `metadata.name`s with no `kubectl apply` collision at the
10028/// shared namespace, mirroring the peer CNP `metadata.name` collision
10029/// posture the sibling [`cilium_network_policy_name`] composer's
10030/// docstring names).
10031#[must_use]
10032pub fn gateway_api_http_route_name(aplicacao: &str, para: &str) -> String {
10033    format!("{aplicacao}-{para}")
10034}
10035
10036/// Canonical K8s API key naming the resource's API-version selector
10037/// (e.g. `cilium.io/v2`, `gateway.networking.k8s.io/v1`,
10038/// `wasm.pleme.io/v1alpha1`). Lifted to a const so a future API-server
10039/// rename or a multi-version-skew migration is a one-line edit, not a
10040/// search-and-replace across every per-target renderer.
10041pub const KUBE_KEY_API_VERSION: &str = "apiVersion";
10042/// Canonical K8s API key naming the resource's kind discriminator
10043/// (e.g. `CiliumNetworkPolicy`, `Gateway`, `HTTPRoute`, `ComputeUnit`).
10044pub const KUBE_KEY_KIND: &str = "kind";
10045/// Canonical K8s API key naming the resource's metadata block.
10046pub const KUBE_KEY_METADATA: &str = "metadata";
10047/// Canonical K8s API key naming the resource's name (under metadata).
10048pub const KUBE_KEY_NAME: &str = "name";
10049/// Canonical K8s API key naming the resource's namespace (under metadata).
10050pub const KUBE_KEY_NAMESPACE: &str = "namespace";
10051/// Canonical K8s API key naming the resource's labels (under metadata).
10052pub const KUBE_KEY_LABELS: &str = "labels";
10053/// Canonical K8s API key naming the resource's per-kind body (sibling
10054/// to [`KUBE_KEY_METADATA`] at the K8s CR top level). Every typed
10055/// substrate renderer that materializes a CR populates `spec.*` from
10056/// the source caixa.lisp — caixa-mesh's `cilium_network_policies`
10057/// per-`(:de, :para)` `CiliumNetworkPolicy` emitter (the policy's
10058/// `endpointSelector` / `ingress` block lives under spec),
10059/// caixa-mesh's `gateway_routes` `Gateway` + `HTTPRoute` emitter (the
10060/// listeners / rules / parentRefs block lives under spec),
10061/// caixa-flux's `programs_yaml_entry` + `upsert_into_helmrelease_programs`
10062/// (the fleet `HelmRelease`'s `spec.values.programs[]` axis),
10063/// caixa-helm's `values.yaml` builder (the upstream ComputeUnit YAML's
10064/// `spec.*` axis the rendered `lareira-<nome>` chart re-routes through
10065/// the library alias). Spelled exactly as the K8s apiserver expects
10066/// (the canonical OpenAPI v3 schema property name K8s machinery
10067/// validates against on every CR registration), so the rendered YAML
10068/// round-trips through every K8s schema parser without per-renderer
10069/// string drift. Lifted on the trajectory the peer
10070/// [`KUBE_KEY_API_VERSION`] / [`KUBE_KEY_KIND`] /
10071/// [`KUBE_KEY_METADATA`] / [`KUBE_KEY_NAME`] / [`KUBE_KEY_NAMESPACE`]
10072/// / [`KUBE_KEY_LABELS`] / [`KUBE_KEY_MATCH_LABELS`] canonical-K8s-
10073/// API-key constants establish.
10074pub const KUBE_KEY_SPEC: &str = "spec";
10075/// Canonical K8s API key naming the `matchLabels` axis of a
10076/// [`LabelSelector`][k8s-ls] — the equality-based projection of the
10077/// selector schema (the other axis, `matchExpressions`, is set-based
10078/// and intentionally out-of-scope for the V0 [`label_selector`]
10079/// helper). Spelled exactly as the K8s apiserver expects (camelCase
10080/// `matchLabels`, not `match_labels` / `MatchLabels` / `match-labels`)
10081/// so the rendered YAML round-trips through every K8s schema parser
10082/// (Cilium CRDs, Gateway API, `ComputeUnit`, future
10083/// `mesh.pleme.io/v1alpha1/Aplicacao`) without per-renderer string
10084/// drift.
10085///
10086/// [k8s-ls]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#labelselector-v1-meta
10087pub const KUBE_KEY_MATCH_LABELS: &str = "matchLabels";
10088
10089/// Canonical K8s API key naming the per-CR **`rules` collection** axis —
10090/// the container the apiserver-side OpenAPI schema for every rule-shaped
10091/// CR (Cilium L7 `spec.ingress[].toPorts[].rules`, Gateway API
10092/// `HTTPRoute.spec.rules[]`, RBAC `Role.rules[]` /
10093/// `ClusterRole.rules[]`, and every future rule-list-shaped CR the M4
10094/// `mesh.pleme.io/v1alpha1/Aplicacao` materializer + the per-edge
10095/// `CiliumClusterwideEnvoyConfig` emitter will land on) mounts the
10096/// per-CR list of match/action rules under. Spelled exactly as the K8s
10097/// apiserver expects (lowercase `rules`, not `Rules` / `rule` /
10098/// `ruleset`) so the rendered YAML round-trips through every K8s schema
10099/// parser without per-renderer string drift.
10100///
10101/// Two production-code call sites in this crate's downstream
10102/// [`caixa-mesh`][cm] renderer carry this key on the same
10103/// K8s-rule-list-axis surface (both landing sites lived at inline
10104/// `"rules".into()` before this lift):
10105///
10106/// 1. `cilium_network_policies` — the per-`(:de, :para)`
10107///    `CiliumNetworkPolicy` emitter's per-`toPorts[]` `rules:` mapping
10108///    (the Cilium L7 rule-list container that carries the `http:` /
10109///    `kafka:` / `dns:` per-protocol L7 rules the Cilium data plane
10110///    dispatches on).
10111/// 2. `gateway_routes` — the `HTTPRoute` emitter's top-level
10112///    `spec.rules[]` sequence (the Gateway API rule-list container that
10113///    carries the per-rule `matches[]` + `backendRefs[]` + timeouts /
10114///    retries overlay the gateway-class-controller dispatches on).
10115///
10116/// Five test-side traversal sites in the same renderer navigate the
10117/// rendered mesh bundle's per-CR `rules:` axis to pin per-CR L7-rule /
10118/// Gateway-API-rule presence, absence, and content invariants (the
10119/// `.get("rules")` retrievals under `toPorts[]` on the L7 policy pins
10120/// and under `spec` on the HTTPRoute pins). All seven sites now route
10121/// through this const so a future K8s CRD schema rebrand on the shared
10122/// axis (or the canonical typo footgun `"Rules"` / `"rule"` /
10123/// `"ruleset"`) surfaces at this one const rather than as an admission-
10124/// time silent drop across two distinct CR emitters.
10125///
10126/// Lifted on the trajectory the peer [`KUBE_KEY_API_VERSION`] /
10127/// [`KUBE_KEY_KIND`] / [`KUBE_KEY_METADATA`] / [`KUBE_KEY_NAME`] /
10128/// [`KUBE_KEY_NAMESPACE`] / [`KUBE_KEY_LABELS`] / [`KUBE_KEY_SPEC`] /
10129/// [`KUBE_KEY_MATCH_LABELS`] canonical-K8s-API-key constants establish
10130/// — extends the K8s-CR top-level `(apiVersion, kind, metadata, spec)`
10131/// axis quartet + the nested `metadata.{name, namespace, labels}`
10132/// triplet + the `LabelSelector.matchLabels` selector-projection axis
10133/// onto the load-bearing nested `spec.rules[]` / `toPorts[].rules`
10134/// rule-list container axis every downstream L7-policy /
10135/// HTTPRoute-rule-dispatch consumer of the rendered mesh bundle keys
10136/// off.
10137///
10138/// [cm]: ../../caixa_mesh/index.html
10139pub const KUBE_KEY_RULES: &str = "rules";
10140
10141/// Canonical K8s API key naming the per-CR **L4 port** scalar axis —
10142/// the field the apiserver-side OpenAPI schema for every port-carrying
10143/// CR body-position (Cilium L7 `spec.ingress[].toPorts[].ports[].port`
10144/// per-port-tuple L4 port number, Gateway API
10145/// `Gateway.spec.listeners[].port` per-listener L4 port number,
10146/// Gateway API `HTTPRoute.spec.rules[].backendRefs[].port` per-rule
10147/// per-backend L4 port number, and every future port-shaped CR body-
10148/// position the M4 `mesh.pleme.io/v1alpha1/Aplicacao` materializer +
10149/// the per-edge `CiliumClusterwideEnvoyConfig` emitter will land on)
10150/// mounts the L4 port value under. Spelled exactly as the K8s
10151/// apiserver expects (lowercase `port`, not `Port` / `portNumber` /
10152/// `portValue` / `targetPort` — the L4-port-number axis, distinct
10153/// from the `targetPort` L4-forwarding-destination axis on the K8s
10154/// Service CRD that lives on a sibling field name the port-value
10155/// axis is not) so the rendered YAML round-trips through every K8s
10156/// schema parser without per-renderer string drift.
10157///
10158/// Three production-code call sites in this crate's downstream
10159/// [`caixa-mesh`][cm] renderer carry this key on the same
10160/// K8s-L4-port-scalar-axis surface (all three landing sites lived at
10161/// inline `"port".into()` before this lift):
10162///
10163/// 1. `cilium_network_policies` — the per-`(:de, :para)`
10164///    `CiliumNetworkPolicy` emitter's per-`toPorts[].ports[]` port-
10165///    tuple entry's `port:` scalar (the L4 port number the Cilium
10166///    data plane's per-tuple bpf policy dispatch loop compares
10167///    against the observed TCP/UDP L4 header port value).
10168/// 2. `gateway_routes` — the `Gateway` emitter's per-listener
10169///    `spec.listeners[].port` scalar (the L4 port number the
10170///    gateway-class-controller's per-listener bind loop opens the
10171///    listener socket on).
10172/// 3. `gateway_routes` — the `HTTPRoute` emitter's per-rule
10173///    `spec.rules[].backendRefs[].port` scalar (the L4 port number
10174///    the gateway-class-controller's per-rule backend-dispatch loop
10175///    forwards the matched request to on the resolved Service /
10176///    ExternalName backend).
10177///
10178/// Two test-side traversal sites in the same renderer navigate the
10179/// rendered mesh bundle's per-CR L4-port scalar axis to pin per-CR
10180/// port-value content invariants (the `.get("port")` retrievals under
10181/// `toPorts[].ports[]` on the L7 policy pin threading through
10182/// [`DEFAULT_SERVICO_PORT`] and under `backendRefs[]` on the
10183/// HTTPRoute-backend-port pin). All five sites now route through this
10184/// const so a future K8s CRD schema rebrand on the shared axis (or
10185/// the canonical typo footgun `"Port"` / `"portNumber"` /
10186/// `"portValue"`) surfaces at this one const rather than as an
10187/// admission-time silent drop across three distinct CR emitters.
10188///
10189/// Lifted on the trajectory the peer [`KUBE_KEY_API_VERSION`] /
10190/// [`KUBE_KEY_KIND`] / [`KUBE_KEY_METADATA`] / [`KUBE_KEY_NAME`] /
10191/// [`KUBE_KEY_NAMESPACE`] / [`KUBE_KEY_LABELS`] / [`KUBE_KEY_SPEC`] /
10192/// [`KUBE_KEY_MATCH_LABELS`] / [`KUBE_KEY_RULES`] canonical-K8s-API-
10193/// key constants establish — extends the K8s-CR top-level
10194/// `(apiVersion, kind, metadata, spec)` axis quartet + the nested
10195/// `metadata.{name, namespace, labels}` triplet + the
10196/// `LabelSelector.matchLabels` selector-projection axis + the
10197/// `spec.rules[]` / `toPorts[].rules` rule-list container axis onto
10198/// the load-bearing nested L4-port-scalar axis every downstream
10199/// bpf-policy-dispatch / gateway-listener-bind / gateway-backend-
10200/// dispatch consumer of the rendered mesh bundle keys off.
10201///
10202/// [cm]: ../../caixa_mesh/index.html
10203pub const KUBE_KEY_PORT: &str = "port";
10204
10205/// Canonical K8s API key naming the per-CR **L4/L7 protocol**
10206/// scalar-discriminator axis — the field the apiserver-side `OpenAPI`
10207/// schema for every protocol-carrying CR body-position (Cilium L7
10208/// `spec.ingress[].toPorts[].ports[].protocol` per-port-tuple L4
10209/// transport protocol discriminator picking between `TCP` / `UDP` /
10210/// `SCTP` / `ANY`, Gateway API `Gateway.spec.listeners[].protocol`
10211/// per-listener L7 listener-protocol discriminator picking between
10212/// `HTTP` / `HTTPS` / `TCP` / `TLS` / `UDP`, and every future
10213/// protocol-shaped CR body-position the M4
10214/// `mesh.pleme.io/v1alpha1/Aplicacao` materializer + the per-edge
10215/// `CiliumClusterwideEnvoyConfig` emitter will land on) mounts the
10216/// protocol-value discriminator under. Spelled exactly as the K8s
10217/// apiserver expects (lowercase `protocol`, not `Protocol` /
10218/// `proto` / `transportProtocol` — the singular scalar-key
10219/// convention K8s uses across every protocol-carrying CR family,
10220/// distinct from the `protocols[]` plural-container axis used on a
10221/// few application-layer-protocol CRDs which is not this axis) so
10222/// the rendered YAML round-trips through every K8s schema parser
10223/// without per-renderer string drift.
10224///
10225/// Two production-code call sites in this crate's downstream
10226/// [`caixa-mesh`][cm] renderer carry this key on the same
10227/// K8s-protocol-scalar-axis surface (both landing sites lived at
10228/// inline `"protocol".into()` before this lift):
10229///
10230/// 1. `cilium_network_policies` — the per-`(:de, :para)`
10231///    `CiliumNetworkPolicy` emitter's per-`toPorts[].ports[]` port-
10232///    tuple entry's `protocol:` scalar (the L4 transport protocol
10233///    discriminator the Cilium data plane's per-tuple bpf policy
10234///    dispatch loop compares against the observed L4 header
10235///    protocol before applying the port match — a drifted key here
10236///    makes the per-tuple bpf policy fall back to the CRD default
10237///    `ANY`, silently admitting UDP traffic through a TCP-only
10238///    rule).
10239/// 2. `gateway_routes` — the `Gateway` emitter's per-listener
10240///    `spec.listeners[].protocol` scalar (the L7 listener protocol
10241///    discriminator the gateway-class-controller's per-listener
10242///    bind loop selects the L7 parser + TLS termination strategy
10243///    from — a drifted key here silently fails the listener
10244///    validation, the gateway-class-controller rejects the entire
10245///    `Gateway` object at admission time, no L7 traffic admitted).
10246///
10247/// One test-side traversal site in the same renderer navigates the
10248/// rendered mesh bundle's per-CR protocol scalar axis to pin per-CR
10249/// listener-protocol content invariants (the
10250/// `gateway_emits_gateway_plus_httproute_pair` `.get("protocol")`
10251/// retrieval on the emitted `Gateway`'s first listener pinning the
10252/// canonical `HTTP` listener-protocol value). All three sites now
10253/// route through this const so a future K8s CRD schema rebrand on
10254/// the shared axis (or the canonical typo footgun `"Protocol"` /
10255/// `"proto"` / `"transportProtocol"`) surfaces at this one const
10256/// rather than as an admission-time silent drop across two distinct
10257/// CR emitters.
10258///
10259/// Lifted on the trajectory the peer [`KUBE_KEY_API_VERSION`] /
10260/// [`KUBE_KEY_KIND`] / [`KUBE_KEY_METADATA`] / [`KUBE_KEY_NAME`] /
10261/// [`KUBE_KEY_NAMESPACE`] / [`KUBE_KEY_LABELS`] / [`KUBE_KEY_SPEC`] /
10262/// [`KUBE_KEY_MATCH_LABELS`] / [`KUBE_KEY_RULES`] /
10263/// [`KUBE_KEY_PORT`] canonical-K8s-API-key constants establish —
10264/// extends the K8s-CR top-level `(apiVersion, kind, metadata, spec)`
10265/// axis quartet + the nested `metadata.{name, namespace, labels}`
10266/// triplet + the `LabelSelector.matchLabels` selector-projection
10267/// axis + the `spec.rules[]` / `toPorts[].rules` rule-list container
10268/// axis + the L4-port-scalar axis onto the load-bearing nested
10269/// L4/L7-protocol-scalar-discriminator axis every downstream bpf-
10270/// policy-dispatch / gateway-listener-bind consumer of the rendered
10271/// mesh bundle keys off before it can commit to a port match or a
10272/// listener parser.
10273///
10274/// [cm]: ../../caixa_mesh/index.html
10275pub const KUBE_KEY_PROTOCOL: &str = "protocol";
10276
10277/// Canonical K8s API key naming the per-CR **discriminated-union type**
10278/// scalar-discriminator axis — the field the apiserver-side OpenAPI schema
10279/// for every discriminated-union CR body-position (Gateway API v1
10280/// `HTTPRouteMatch.path.type` per-`HTTPRouteMatch` path-selection-predicate
10281/// discriminator picking between `Exact` / `PathPrefix` /
10282/// `RegularExpression`, K8s core `Condition.type` per-condition kind
10283/// discriminator, K8s core `Volume.<projection>.type` per-projection
10284/// content-source discriminator, and every future discriminated-union CR
10285/// body-position the M4 `mesh.pleme.io/v1alpha1/Aplicacao` materializer
10286/// + the per-edge `CiliumClusterwideEnvoyConfig` emitter's per-listener
10287/// filter-chain type-discriminator + a future per-`:entrada :paths`
10288/// typed slot admitting a per-path `(:predicate <Exact|Prefix|Regex>)`
10289/// axis will land on) mounts the discriminated-union type-value under.
10290/// Spelled exactly as the K8s apiserver expects (lowercase `type`, not
10291/// `Type` / `kind` / `discriminator` — the singular scalar-key
10292/// convention K8s uses across every discriminated-union CR family,
10293/// distinct from the top-level [`KUBE_KEY_KIND`] CRD-registration
10294/// discriminator on the K8s CR top-level which is the CRD-lookup half
10295/// of the `(apiVersion, kind)` tuple the K8s apiserver's `RESTMapper`
10296/// consults and is not this axis) so the rendered YAML round-trips
10297/// through every K8s schema parser without per-renderer string drift.
10298///
10299/// One production-code call site in this crate's downstream
10300/// [`caixa-mesh`][cm] renderer carries this key on the same
10301/// K8s-discriminated-union-type-scalar-axis surface (the landing site
10302/// lived at an inline `"type".into()` before this lift):
10303///
10304/// 1. `gateway_routes` — the `HTTPRoute` emitter's per-rule per-match
10305///    `spec.rules[].matches[].path.type` scalar (the path-selection-
10306///    predicate discriminator the gateway-class-controller's per-rule
10307///    L7 dispatch pass selects the path-match strategy from — a drifted
10308///    key here silently fails the per-match path-selection-predicate
10309///    validation, the Gateway API v1 `PathMatchType` OpenAPI schema
10310///    validator drops the entire `HTTPRoute` object at admission with
10311///    no per-rule L7 URL-path filtering applied, and every external
10312///    `:entrada` path-filtered flow the route was authored to accept
10313///    drops at the gateway-class-controller's admission gate with no
10314///    field naming the discriminator-drift root cause).
10315///
10316/// Pairs with the sibling [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`]
10317/// (530705d) per-`HTTPRouteMatch` path-selection-predicate discriminator
10318/// scalar-VALUE the discriminator scalar-KEY here holds under, closing
10319/// the per-`HTTPRouteMatch` path-selection-predicate `(type key →
10320/// PathPrefix value)` scalar-key/scalar-value discriminator axis pair
10321/// the M3 Aplicacao mesh renderer's external `:entrada` per-path
10322/// L7-filtering ingress contract rests on — the same shape the sibling
10323/// [`KUBE_KEY_PROTOCOL`] (0307950) key + [`KUBE_PROTOCOL_TCP`] (2123047)
10324/// / [`GATEWAY_API_PROTOCOL_HTTP`] (1b57473) value pair already carries
10325/// on the L4/L7-protocol scalar-discriminator surface. A `"Type"` /
10326/// `"kind"` / `"discriminator"` / `"predicate"` typo at the production-
10327/// code call site lands outside the Gateway API v1 `HTTPPathMatch`
10328/// OpenAPI schema's admitted property set, surfacing apply-side as a
10329/// non-self-locating "spec.rules[0].matches[0].path: Unknown field
10330/// \"Type\"" apiserver admission-rejection far from the source
10331/// `caixa.lisp` / the renderer's `path_match.insert(…)` call site.
10332///
10333/// Lifted on the trajectory the peer [`KUBE_KEY_API_VERSION`] /
10334/// [`KUBE_KEY_KIND`] / [`KUBE_KEY_METADATA`] / [`KUBE_KEY_NAME`] /
10335/// [`KUBE_KEY_NAMESPACE`] / [`KUBE_KEY_LABELS`] / [`KUBE_KEY_SPEC`] /
10336/// [`KUBE_KEY_MATCH_LABELS`] / [`KUBE_KEY_RULES`] / [`KUBE_KEY_PORT`] /
10337/// [`KUBE_KEY_PROTOCOL`] canonical-K8s-API-key constants establish —
10338/// extends the K8s-CR top-level `(apiVersion, kind, metadata, spec)`
10339/// axis quartet + the nested `metadata.{name, namespace, labels}`
10340/// triplet + the `LabelSelector.matchLabels` selector-projection axis
10341/// + the `spec.rules[]` / `toPorts[].rules` rule-list container axis +
10342/// the L4-port-scalar axis + the L4/L7-protocol-scalar-discriminator
10343/// axis onto the load-bearing nested discriminated-union-type-scalar-
10344/// discriminator axis every downstream gateway-class-controller /
10345/// apiserver-side OpenAPI-schema-validator consumer of the rendered
10346/// mesh bundle keys off before it can commit to a per-match path-
10347/// selection predicate.
10348///
10349/// [cm]: ../../caixa_mesh/index.html
10350pub const KUBE_KEY_TYPE: &str = "type";
10351
10352/// Default cluster-wide K8s namespace every caixa renderer emits
10353/// objects into when the source caixa doesn't pin its own. The single
10354/// source of truth both [`caixa-flux`][cf]'s programs.yaml /
10355/// GitRepository / HelmRelease / Kustomization emitters and
10356/// [`caixa-mesh`][cm]'s programs fan-out / CiliumNetworkPolicy /
10357/// Gateway / HTTPRoute emitters consult — re-exported by each
10358/// renderer's lib as `pub use caixa_core::DEFAULT_NAMESPACE`, so a
10359/// future per-cluster-namespace rebrand (e.g. moving to `pleme-system`
10360/// once `tatara-system` outlives its scoping intent) is a one-line
10361/// edit here, not a coordinated rewrite across every renderer
10362/// crate's `metadata.namespace` slot.
10363///
10364/// Until this lift landed both renderers carried their own `pub const
10365/// DEFAULT_NAMESPACE: &str = "tatara-system"` declarations
10366/// (caixa-flux/src/lib.rs:77, caixa-mesh/src/lib.rs:172), with the
10367/// `caixa-mesh` site's doc-comment explicitly acknowledging the
10368/// duplication ("Mirrors `caixa_flux::DEFAULT_NAMESPACE`"); a future
10369/// rebrand on either side without a coordinated edit on the other
10370/// would have silently emitted into two distinct namespaces on the
10371/// same cluster's apply — Servicos at programs.yaml's namespace,
10372/// their Aplicacao's NetworkPolicies / Gateways / HTTPRoutes at a
10373/// drifted one — and the CiliumNetworkPolicy's `endpointSelector`
10374/// would match no pods (different namespace), silently dropping every
10375/// L7 contrato flow at apply time with no diagnostic naming the
10376/// namespace-drift root cause.
10377///
10378/// Lifting it to caixa-core's render-constants block alongside the
10379/// peer [`LABEL_APLICACAO`] / [`LABEL_PROGRAM`] / [`LABEL_CONTRATO`]
10380/// label-namespace constants and the canonical [`KUBE_KEY_NAMESPACE`]
10381/// API-key constant makes the namespace-axis discipline structural:
10382/// every renderer that reaches for the default namespace consults the
10383/// same `&'static str`, and every future renderer (the M4
10384/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer, the future
10385/// per-edge `CiliumClusterwideEnvoyConfig` emitter, the future
10386/// caixa-otel collector-pipeline emitter) inherits the same value by
10387/// construction, with no opportunity for per-renderer drift. Same
10388/// "the typed constant lives in one place" discipline the
10389/// [`PLEME_LABEL_PREFIX`] (a8d4d57) and [`KUBE_KEY_API_VERSION`] /
10390/// [`KUBE_KEY_KIND`] / [`KUBE_KEY_METADATA`] lifts apply on the peer
10391/// shared-string axes.
10392///
10393/// [cf]: ../../caixa_flux/index.html
10394/// [cm]: ../../caixa_mesh/index.html
10395pub const DEFAULT_NAMESPACE: &str = "tatara-system";
10396
10397/// Canonical FluxCD installation namespace every `caixa-flux` `Kustomization`
10398/// document apply-targets. The single source of truth both axes of the
10399/// rendered `kustomization.yaml` document reach for:
10400///
10401///   - `metadata.namespace` — the namespace the `Kustomization` resource
10402///     itself lives in (the `FluxCD` `kustomize-controller` watches this
10403///     namespace by default; a drifted value sits outside the controller's
10404///     watch window and is never reconciled);
10405///   - `spec.sourceRef.name` — the `GitRepository` the bootstrap pipeline
10406///     created at `flux bootstrap` time and the per-Servico `Kustomization`
10407///     transitively threads its `path: ./clusters/<cluster>/services/<name>`
10408///     reference through. The canonical FluxCD bootstrap convention names
10409///     this `GitRepository` after the installation namespace (the
10410///     `flux-system` namespace contains a `GitRepository/flux-system`
10411///     pointing at the operator's source-of-truth repo); both axes are the
10412///     same conceptual "Flux installation namespace" load-bearing string
10413///     and must move together on any future rebrand.
10414///
10415/// Until this lift landed both axes carried inline `flux-system` literals
10416/// inside [`cluster_bundle`]'s `kustomization.yaml` format-string template
10417/// (caixa-flux/src/lib.rs:477, 483) — two production-code consumers of the
10418/// same load-bearing FluxCD-installation-namespace convention, drift-prone
10419/// by construction. A future per-cluster Flux installation rebrand (the
10420/// operator moving the bootstrap controllers to a different installation
10421/// namespace, e.g. `flux-pleme` to match the per-tenant scoping convention
10422/// once `flux-system` outlives its scoping intent; or any per-edition
10423/// rebrand the FluxCD upgrade docs name) on one axis without a coordinated
10424/// edit on the other would have silently emitted a `Kustomization` whose
10425/// `metadata.namespace` sat outside the `kustomize-controller` watch
10426/// window (controller-side: never reconciled, every `HelmRelease` /
10427/// `GitRepository` it gates frozen at last-applied state) or whose
10428/// `spec.sourceRef.name` pointed at a `GitRepository` that doesn't exist
10429/// in the rebranded namespace (apply-side: the reference dangles, the
10430/// dependent chart never pulls). The apply-time symptom (the Servico's
10431/// `HelmRelease` is created but never reconciled, or never reaches its
10432/// chart source) is invisible at admission and surfaces only as
10433/// "the cluster says the resources are applied but nothing changed",
10434/// typically far from the rebrand commit's source.
10435///
10436/// Lifting it to caixa-core's render-constants block alongside the peer
10437/// [`DEFAULT_NAMESPACE`] (a085b26, the workload-side
10438/// `tatara-system` namespace every emitted resource lives in) makes the
10439/// installation-namespace axis discipline structural: both kustomization
10440/// axes consult the same `&'static str`, and every future renderer that
10441/// reaches for the canonical Flux installation namespace (the future M4
10442/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
10443/// `Kustomization`, the future per-edge `Kustomization` the operator
10444/// emits for the `CiliumClusterwideEnvoyConfig` pipeline, the future
10445/// `caixa-otel` collector-pipeline `Kustomization`) inherits the same
10446/// value by construction with no opportunity for per-renderer drift.
10447/// Same "the typed constant lives in one place" discipline the
10448/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
10449/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
10450/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) lifts apply on the
10451/// peer canonical-load-bearing-string surface.
10452///
10453/// The value is a valid DNS-1123 label (the K8s apiserver-side floor every
10454/// `metadata.namespace` rule enforces): lowercase ASCII alphanumeric with
10455/// `-` separators, no leading / trailing hyphen, length within the
10456/// [`DNS_1123_LABEL_MAX_LEN`] (63-byte) cap. A future rebrand on this lift
10457/// cannot silently land a value the apiserver refuses, by construction:
10458/// the [`default_flux_system_namespace_is_a_valid_dns_1123_label`] pin
10459/// trips at caixa-core build time on any drift past the typed floor.
10460///
10461/// [cf]: ../../caixa_flux/index.html
10462pub const DEFAULT_FLUX_SYSTEM_NAMESPACE: &str = "flux-system";
10463
10464/// Canonical FluxCD `HelmRelease` CRD `apiVersion` every `caixa-flux`
10465/// `helmrelease.yaml` document emits. The Flux v2 `helm-controller` watches
10466/// resources at this exact group/version (`helm.toolkit.fluxcd.io/v2`);
10467/// drift to a stale `v2beta1` / `v2beta2` (the pre-GA Flux v2 betas every
10468/// upstream Flux GA-migration doc names) silently routes the rendered
10469/// `HelmRelease` outside the controller's `Watches` and breaks at apply
10470/// time with a non-self-locating "no kind 'HelmRelease' is registered for
10471/// version 'helm.toolkit.fluxcd.io/v2beta2'" error far from the source
10472/// caixa.lisp / the renderer's format-string template.
10473///
10474/// The single source of truth both axes of the rendered Flux bundle reach
10475/// for:
10476///
10477///   - `helmrelease.yaml` `apiVersion` — the top-level CRD-group/version
10478///     the rendered document declares (caixa-flux/src/lib.rs:455 — the
10479///     `helmrelease` format-string template);
10480///   - `kustomization.yaml` `spec.healthChecks[]` per-entry `apiVersion`
10481///     — the same Flux-v2 `HelmRelease` reference the parent Kustomization
10482///     gates its health-check on (caixa-flux/src/lib.rs:504 — the
10483///     `kustomization` format-string template). The Flux v2 contract pairs
10484///     a `HelmRelease` document with its sibling `Kustomization`'s
10485///     `healthChecks[].apiVersion` axis: both must name the same Flux v2
10486///     `HelmRelease` CRD group/version for the Kustomization's per-resource
10487///     health-gate to bind to the rendered HelmRelease; a future Flux v3
10488///     promotion (the upstream Flux roadmap names a per-CRD-group / per-
10489///     v3 version migration once the Flux v2 LTS branch closes) on one
10490///     axis without a coordinated edit on the other would have silently
10491///     emitted a `Kustomization` whose `healthChecks[].apiVersion` pointed
10492///     at an obsolete CRD group/version (apply-side: the health check
10493///     never resolves, the parent Kustomization sits perpetually in
10494///     `Reconciling`).
10495///
10496/// Until this lift landed both axes carried inline
10497/// `helm.toolkit.fluxcd.io/v2` literals inside [`cluster_bundle`]'s
10498/// `helmrelease.yaml` + `kustomization.yaml` format-string templates and a
10499/// matching pair inside the in-file `upsert_into_helmrelease_programs`
10500/// test fixtures (caixa-flux/src/lib.rs:928, 970) — four occurrences of
10501/// the same load-bearing FluxCD-CRD-group/version convention, drift-prone
10502/// by construction. The PRIME DIRECTIVE duplication-budget rule
10503/// (THEORY.md §I.3.5: "every recurring shape becomes a generator before
10504/// it becomes a pattern; every pattern becomes a library before it
10505/// becomes duplicated code. The duplication budget is zero.") promotes
10506/// the constant to a typed substrate-side `&'static str` on the same
10507/// trajectory the [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lift
10508/// established on the sibling Flux-installation-namespace axis. The two
10509/// render-side consumers now thread the same `&'static str` through their
10510/// format-string templates so a future Flux v3 promotion lands in one
10511/// place; the test fixtures keep the value as a literal because they
10512/// exercise `serde_yaml::from_str` on a static YAML document — the
10513/// build-time pin [`default_flux_helmrelease_api_version_matches_caixa_flux_test_fixtures`]
10514/// trips if the literals ever drift past the typed const.
10515///
10516/// Same "the typed constant lives in one place" discipline the
10517/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
10518/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
10519/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
10520/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts apply on the peer
10521/// canonical-load-bearing-string surface.
10522///
10523/// [cf]: ../../caixa_flux/index.html
10524pub const FLUX_HELMRELEASE_API_VERSION: &str = "helm.toolkit.fluxcd.io/v2";
10525
10526/// Canonical FluxCD `GitRepository` CRD `apiVersion` every `caixa-flux`
10527/// `gitrepository.yaml` document emits. The Flux v2 `source-controller`
10528/// watches resources at this exact group/version
10529/// (`source.toolkit.fluxcd.io/v1`); drift to a stale `v1beta1` / `v1beta2`
10530/// (the pre-GA Flux v2 source-controller betas every upstream Flux GA-
10531/// migration doc names) silently routes the rendered `GitRepository`
10532/// outside the controller's `Watches` and breaks at apply time with a
10533/// non-self-locating "no kind 'GitRepository' is registered for version
10534/// 'source.toolkit.fluxcd.io/v1beta2'" error far from the source
10535/// caixa.lisp / the renderer's format-string template.
10536///
10537/// The single source of truth the `gitrepository.yaml` `apiVersion` axis
10538/// reaches for (caixa-flux/src/lib.rs:436 — the `gitrepo` format-string
10539/// template). The Flux v2 source/helm/kustomize controller triple pairs
10540/// each CRD-group/version against its sibling controller's `Watches`
10541/// registration: the rendered `GitRepository` is the chart-source the
10542/// sibling `HelmRelease` document's `spec.chart.spec.sourceRef.kind:
10543/// GitRepository` references, and the parent `Kustomization`'s
10544/// `spec.sourceRef.kind: GitRepository` also points at this same CRD
10545/// group/version. A future Flux v3 promotion on this axis without a
10546/// coordinated edit on the sibling [`FLUX_HELMRELEASE_API_VERSION`] /
10547/// future-`FLUX_KUSTOMIZATION_API_VERSION` axes would silently land the
10548/// rendered `GitRepository` outside the source-controller's `Watches`
10549/// (controller-side: never reconciled, the dependent HelmRelease's
10550/// `chart: sourceRef` dangles, every per-Servico apply silently comes
10551/// up with the prior reconciled state).
10552///
10553/// Until this lift landed the axis carried an inline
10554/// `source.toolkit.fluxcd.io/v1` literal inside [`cluster_bundle`]'s
10555/// `gitrepository.yaml` format-string template — one occurrence today,
10556/// promoted to a typed substrate-side `&'static str` on the same
10557/// trajectory the [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10558/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts established on the
10559/// sibling Flux-v2-load-bearing-string surface. The render-side consumer
10560/// now threads the same `&'static str` through its format-string
10561/// template so a future Flux v3 promotion lands in one place; every
10562/// future renderer that reaches for the canonical Flux v2 `GitRepository`
10563/// apiVersion (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
10564/// materializer's per-Aplicacao `GitRepository`, a future per-edge
10565/// `GitRepository` the operator emits for the
10566/// `CiliumClusterwideEnvoyConfig` pipeline, a future `caixa-otel`
10567/// collector-pipeline `GitRepository`) inherits the same value by
10568/// construction with no opportunity for per-renderer drift.
10569///
10570/// Same "the typed constant lives in one place" discipline the
10571/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
10572/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
10573/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
10574/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) /
10575/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) lifts apply on the peer
10576/// canonical-load-bearing-string surface.
10577///
10578/// [cf]: ../../caixa_flux/index.html
10579pub const FLUX_GITREPOSITORY_API_VERSION: &str = "source.toolkit.fluxcd.io/v1";
10580
10581/// Canonical FluxCD `GitRepository` CRD `kind` discriminator every
10582/// `caixa-flux`-emitted document that names a Flux v2 `GitRepository`
10583/// at a [`KUBE_KEY_KIND`]-rooted axis declares. Paired peer to the
10584/// sibling [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) — the K8s
10585/// apiserver-side CRD resolution contract is the `(apiVersion, kind)`
10586/// tuple keyed against the registered `CustomResourceDefinition`, so
10587/// drift on the kind axis is exactly as load-bearing as drift on the
10588/// apiVersion axis it accompanies (the apiserver's `RESTMapper` consults
10589/// both together; a `("source.toolkit.fluxcd.io/v1", "GitRepostiory")`
10590/// typo at any one of the three production-code call sites lands
10591/// outside the registered Flux v2 source-controller CRD's
10592/// `RESTKind` lookup, surfacing apply-side as a non-self-locating
10593/// "no kind 'GitRepostiory' is registered for version
10594/// 'source.toolkit.fluxcd.io/v1'" error far from the source
10595/// caixa.lisp / the renderer's format-string template).
10596///
10597/// The single source of truth the rendered Flux bundle's three
10598/// `GitRepository`-naming axes reach for:
10599///
10600///   - the rendered `gitrepository.yaml` document's top-level
10601///     [`KUBE_KEY_KIND`] axis (caixa-flux/src/lib.rs:505 — the
10602///     `gitrepo` format-string template);
10603///   - the rendered `helmrelease.yaml` document's
10604///     `spec.chart.spec.sourceRef.kind` axis (caixa-flux/src/lib.rs:556 —
10605///     the `helmrelease` format-string template), pointing back at the
10606///     sibling `GitRepository` the chart sources from;
10607///   - the rendered `kustomization.yaml` document's `spec.sourceRef.kind`
10608///     axis (caixa-flux/src/lib.rs:591 — the `kustomization` format-
10609///     string template), pointing back at the cluster's bootstrap
10610///     `GitRepository` (paired with [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
10611///     on the namespace axis).
10612///
10613/// All three axes name the same K8s CRD discriminator and must move
10614/// together on any future Flux v3 rebrand (e.g. an upstream Flux v3
10615/// rename like `GitSource`). Until this lift landed the three axes
10616/// carried inline `GitRepository` literals across the three production-
10617/// code occurrences in caixa-flux/src/lib.rs:505, 556, 591 (the
10618/// `cluster_bundle` `gitrepo` + `helmrelease` + `kustomization` format-
10619/// string templates) plus a matching set inside the in-file
10620/// `cluster_bundle_*` test fixtures — six occurrences of the same load-
10621/// bearing FluxCD-CRD-`kind`-discriminator convention, drift-prone by
10622/// construction. A drift on the `helmrelease.yaml`
10623/// `spec.chart.spec.sourceRef.kind` site alone — the one apply-side
10624/// failure mode the apiserver can't self-locate — would have silently
10625/// dangled the HelmRelease's chart sourceRef (controller-side: the
10626/// `helm-controller` never resolves a chart for the HelmRelease, the
10627/// rendered Servico chart never reconciles, every per-Servico apply
10628/// silently comes up with the prior reconciled state) with no diagnostic
10629/// naming the kind-drift root cause far from the source caixa.lisp.
10630///
10631/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
10632/// "every recurring shape becomes a generator before it becomes a
10633/// pattern; every pattern becomes a library before it becomes
10634/// duplicated code. The duplication budget is zero.") promotes the
10635/// constant to a typed substrate-side `&'static str` on the same
10636/// trajectory the [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10637/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10638/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) lifts established on
10639/// the sibling Flux-v2-load-bearing-string axes — extends the
10640/// discipline from the apiVersion half of the `(apiVersion, kind)`
10641/// CRD-lookup tuple onto the kind half on the same Flux v2
10642/// source-controller CRD. The three render-side consumers now thread
10643/// the same `&'static str` through their format-string templates so a
10644/// future Flux v3 rebrand lands in one place; every future renderer
10645/// that reaches for the canonical Flux v2 `GitRepository` kind (the
10646/// future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
10647/// per-Aplicacao `GitRepository`, a future per-edge `GitRepository`
10648/// the operator emits for the `CiliumClusterwideEnvoyConfig` pipeline,
10649/// a future `caixa-otel` collector-pipeline `GitRepository`) inherits
10650/// the same value by construction with no opportunity for per-renderer
10651/// drift.
10652///
10653/// Same "the typed constant lives in one place" discipline the
10654/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10655/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10656/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
10657/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts apply on the peer
10658/// canonical-Flux-v2-load-bearing-string surface.
10659///
10660/// [cf]: ../../caixa_flux/index.html
10661pub const FLUX_KIND_GIT_REPOSITORY: &str = "GitRepository";
10662
10663/// Canonical FluxCD `HelmRelease` CRD `kind` discriminator every
10664/// `caixa-flux`-emitted document that names a Flux v2 `HelmRelease`
10665/// at a [`KUBE_KEY_KIND`]-rooted axis declares. Paired peer to the
10666/// sibling [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) — the K8s
10667/// apiserver-side CRD resolution contract is the `(apiVersion, kind)`
10668/// tuple keyed against the registered `CustomResourceDefinition`, so
10669/// drift on the kind axis is exactly as load-bearing as drift on the
10670/// apiVersion axis it accompanies (the apiserver's `RESTMapper`
10671/// consults both together; a `("helm.toolkit.fluxcd.io/v2",
10672/// "HelmRelase")` typo at any one of the two production-code call
10673/// sites lands outside the registered Flux v2 helm-controller CRD's
10674/// `RESTKind` lookup, surfacing apply-side as a non-self-locating
10675/// "no kind 'HelmRelase' is registered for version
10676/// 'helm.toolkit.fluxcd.io/v2'" error far from the source
10677/// caixa.lisp / the renderer's format-string template).
10678///
10679/// The single source of truth the rendered Flux bundle's two
10680/// `HelmRelease`-naming axes reach for:
10681///
10682///   - the rendered `helmrelease.yaml` document's top-level
10683///     [`KUBE_KEY_KIND`] axis (caixa-flux/src/lib.rs:580 — the
10684///     `helmrelease` format-string template);
10685///   - the rendered `kustomization.yaml` document's
10686///     `spec.healthChecks[].kind` axis (caixa-flux/src/lib.rs:631 —
10687///     the `kustomization` format-string template), pointing back at
10688///     the sibling `HelmRelease` the Kustomization pins as a
10689///     health-gate before declaring its own reconcile complete.
10690///
10691/// Both axes name the same K8s CRD discriminator and must move
10692/// together on any future Flux v3 rebrand (e.g. an upstream Flux v3
10693/// rename like `ChartRelease`). Until this lift landed the two axes
10694/// carried inline `HelmRelease` literals across the two production-
10695/// code occurrences in caixa-flux/src/lib.rs:580 (the
10696/// `cluster_bundle` `helmrelease` format-string template) and 631
10697/// (the `kustomization` `spec.healthChecks[]` element). A drift on
10698/// the `kustomization.yaml` `spec.healthChecks[].kind` site alone —
10699/// the one apply-side failure mode the apiserver can't self-locate
10700/// (a healthCheck kind typo doesn't fail apply-parse the way a
10701/// top-level kind typo does; it sits as a dangling unmatched health
10702/// gate the `kustomize-controller` perpetually re-evaluates) —
10703/// would have silently pinned the parent Kustomization at
10704/// `Reconciling` forever with no diagnostic naming the kind-drift
10705/// root cause far from the source caixa.lisp.
10706///
10707/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
10708/// "every recurring shape becomes a generator before it becomes a
10709/// pattern; every pattern becomes a library before it becomes
10710/// duplicated code. The duplication budget is zero.") promotes the
10711/// constant to a typed substrate-side `&'static str` on the same
10712/// trajectory the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
10713/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10714/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10715/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) lifts established on
10716/// the sibling Flux-v2-load-bearing-string axes — extends the
10717/// discipline from the kind axis of the Flux v2 source-controller
10718/// CRD (the [`FLUX_KIND_GIT_REPOSITORY`] lift) onto the kind axis of
10719/// the sibling Flux v2 helm-controller CRD. The two render-side
10720/// consumers now thread the same `&'static str` through their
10721/// format-string templates so a future Flux v3 rebrand lands in one
10722/// place; every future renderer that reaches for the canonical Flux
10723/// v2 `HelmRelease` kind (the future M4
10724/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-
10725/// Aplicacao `HelmRelease`, a future per-edge `HelmRelease` the
10726/// operator emits for the `CiliumClusterwideEnvoyConfig` pipeline,
10727/// a future `caixa-otel` collector-pipeline `HelmRelease`) inherits
10728/// the same value by construction with no opportunity for per-
10729/// renderer drift.
10730///
10731/// Same "the typed constant lives in one place" discipline the
10732/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
10733/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10734/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10735/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
10736/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts apply on the
10737/// peer canonical-Flux-v2-load-bearing-string surface.
10738///
10739/// [cf]: ../../caixa_flux/index.html
10740pub const FLUX_KIND_HELM_RELEASE: &str = "HelmRelease";
10741
10742/// Canonical FluxCD `Kustomization` CRD `apiVersion` every `caixa-flux`
10743/// `kustomization.yaml` document emits. The Flux v2 `kustomize-controller`
10744/// watches resources at this exact group/version
10745/// (`kustomize.toolkit.fluxcd.io/v1`); drift to a stale `v1beta1` /
10746/// `v1beta2` (the pre-GA Flux v2 kustomize-controller betas every
10747/// upstream Flux GA-migration doc names) silently routes the rendered
10748/// `Kustomization` outside the controller's `Watches` and breaks at
10749/// apply time with a non-self-locating "no kind 'Kustomization' is
10750/// registered for version 'kustomize.toolkit.fluxcd.io/v1beta2'" error
10751/// far from the source caixa.lisp / the renderer's format-string
10752/// template.
10753///
10754/// The single source of truth the `kustomization.yaml` `apiVersion`
10755/// axis reaches for (caixa-flux/src/lib.rs:531 — the `kustomization`
10756/// format-string template). Completes the Flux v2 controller triplet
10757/// (source-controller + helm-controller + kustomize-controller) lift
10758/// alongside the sibling [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3)
10759/// and [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) — every per-
10760/// controller CRD-group/version is now a typed substrate-side
10761/// `&'static str` consumed through one `pub use caixa_core::FLUX_*`
10762/// re-export at the renderer site. The three controllers share the
10763/// canonical `.toolkit.fluxcd.io` root (asserted by
10764/// [`tests::flux_controller_triplet_api_versions_share_toolkit_fluxcd_io_root`]),
10765/// so a future Flux v3 promotion that forks any controller out of the
10766/// toolkit group surfaces here as a coordinated cross-axis edit-point
10767/// across all three constants.
10768///
10769/// The rendered `Kustomization`'s `metadata.namespace` (the Flux
10770/// installation namespace, [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] —
10771/// 7197d38) and `spec.sourceRef.kind: GitRepository`
10772/// (referenced through [`FLUX_GITREPOSITORY_API_VERSION`]) and
10773/// `spec.healthChecks[].apiVersion` (the rendered `HelmRelease`'s
10774/// CRD-group/version, [`FLUX_HELMRELEASE_API_VERSION`]) all share
10775/// the cluster-side contract with the upstream Flux v2 controller
10776/// triplet: a coordinated edit on any one of these four constants
10777/// must move alongside the sibling axes, and the lift makes that
10778/// movement a typed substrate-side edit-point rather than a
10779/// distributed-across-format-string-template-literals refactor.
10780///
10781/// Until this lift landed the axis carried an inline
10782/// `kustomize.toolkit.fluxcd.io/v1` literal inside [`cluster_bundle`]'s
10783/// `kustomization.yaml` format-string template — one occurrence today,
10784/// promoted to a typed substrate-side `&'static str` on the same
10785/// trajectory the [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10786/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10787/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts established on
10788/// the sibling Flux-v2-load-bearing-string surface. The render-side
10789/// consumer now threads the same `&'static str` through its
10790/// format-string template so a future Flux v3 promotion lands in one
10791/// place; every future renderer that reaches for the canonical Flux
10792/// v2 `Kustomization` apiVersion (the future M4
10793/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
10794/// `Kustomization`, a future per-edge `Kustomization` the operator
10795/// emits for the `CiliumClusterwideEnvoyConfig` pipeline, a future
10796/// `caixa-otel` collector-pipeline `Kustomization`) inherits the
10797/// same value by construction with no opportunity for per-renderer
10798/// drift.
10799///
10800/// Same "the typed constant lives in one place" discipline the
10801/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
10802/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
10803/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
10804/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) /
10805/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10806/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) lifts apply on the
10807/// peer canonical-load-bearing-string surface.
10808///
10809/// [cf]: ../../caixa_flux/index.html
10810pub const FLUX_KUSTOMIZATION_API_VERSION: &str = "kustomize.toolkit.fluxcd.io/v1";
10811
10812/// Canonical FluxCD `Kustomization` CRD `kind` discriminator every
10813/// `caixa-flux`-emitted document that names a Flux v2 `Kustomization`
10814/// at a [`KUBE_KEY_KIND`]-rooted axis declares. Paired peer to the
10815/// sibling [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) — the K8s
10816/// apiserver-side CRD resolution contract is the `(apiVersion, kind)`
10817/// tuple keyed against the registered `CustomResourceDefinition`, so
10818/// drift on the kind axis is exactly as load-bearing as drift on the
10819/// apiVersion axis it accompanies (the apiserver's `RESTMapper` consults
10820/// both together; a `("kustomize.toolkit.fluxcd.io/v1", "Kustomizaton")`
10821/// typo at the production-code call site lands outside the registered
10822/// Flux v2 kustomize-controller CRD's `RESTKind` lookup, surfacing
10823/// apply-side as a non-self-locating "no kind 'Kustomizaton' is
10824/// registered for version 'kustomize.toolkit.fluxcd.io/v1'" error far
10825/// from the source caixa.lisp / the renderer's format-string template).
10826///
10827/// The single source of truth the rendered Flux bundle's
10828/// `Kustomization`-naming axis reaches for:
10829///
10830///   - the rendered `kustomization.yaml` document's top-level
10831///     [`KUBE_KEY_KIND`] axis (caixa-flux/src/lib.rs:651 — the
10832///     `kustomization` format-string template).
10833///
10834/// The kind axis names the same K8s CRD discriminator as the sibling
10835/// [`FLUX_KUSTOMIZATION_API_VERSION`] apiVersion axis and must move
10836/// together on any future Flux v3 rebrand. Until this lift landed the
10837/// axis carried an inline `Kustomization` literal across the one
10838/// production-code occurrence in caixa-flux/src/lib.rs:651 (the
10839/// `cluster_bundle` `kustomization` format-string template) plus a
10840/// matching set inside the in-file `cluster_bundle_*` test fixtures —
10841/// occurrences of the same load-bearing FluxCD-CRD-`kind`-discriminator
10842/// convention, drift-prone by construction. A drift on the top-level
10843/// `kustomization.yaml` `kind` axis would have surfaced as a
10844/// non-self-locating "no kind 'Kustomizaton' is registered for version
10845/// 'kustomize.toolkit.fluxcd.io/v1'" error far from the source
10846/// caixa.lisp at apply parse time, with the rendered parent Kustomization
10847/// never reconciling and every downstream per-Servico `dependsOn` chain
10848/// freezing at the kustomize-controller's CRD-lookup boundary.
10849///
10850/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
10851/// "every recurring shape becomes a generator before it becomes a
10852/// pattern; every pattern becomes a library before it becomes
10853/// duplicated code. The duplication budget is zero.") promotes the
10854/// constant to a typed substrate-side `&'static str` on the same
10855/// trajectory the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
10856/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
10857/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
10858/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10859/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) lifts established on
10860/// the sibling Flux-v2-load-bearing-string axes — extends the
10861/// discipline from the apiVersion half of the `(apiVersion, kind)`
10862/// CRD-lookup tuple onto the kind half on the same Flux v2
10863/// kustomize-controller CRD. Completes the Flux v2 controller triplet
10864/// kind-axis lift (source-controller + helm-controller +
10865/// kustomize-controller) alongside the sibling
10866/// [`FLUX_KIND_GIT_REPOSITORY`] and [`FLUX_KIND_HELM_RELEASE`] — every
10867/// per-controller CRD `kind` discriminator is now a typed substrate-side
10868/// `&'static str` consumed through one `pub use caixa_core::FLUX_KIND_*`
10869/// re-export at the renderer site. The render-side consumer now threads
10870/// the same `&'static str` through its format-string template so a
10871/// future Flux v3 rebrand lands in one place; every future renderer
10872/// that reaches for the canonical Flux v2 `Kustomization` kind (the
10873/// future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
10874/// per-Aplicacao `Kustomization`, a future per-edge `Kustomization`
10875/// the operator emits for the `CiliumClusterwideEnvoyConfig` pipeline,
10876/// a future `caixa-otel` collector-pipeline `Kustomization`) inherits
10877/// the same value by construction with no opportunity for per-renderer
10878/// drift.
10879///
10880/// Same "the typed constant lives in one place" discipline the
10881/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
10882/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
10883/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10884/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10885/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
10886/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts apply on the peer
10887/// canonical-Flux-v2-load-bearing-string surface.
10888///
10889/// [cf]: ../../caixa_flux/index.html
10890pub const FLUX_KIND_KUSTOMIZATION: &str = "Kustomization";
10891
10892/// Canonical Flux v2 per-`HelmRelease`/`Kustomization` source-reference
10893/// container-axis key every `caixa-flux`-emitted bundle document mounts its
10894/// per-CR source-of-truth pointer under (`spec.chart.spec.sourceRef` on
10895/// `HelmRelease`, `spec.sourceRef` on `Kustomization`) — the Flux v2 CRD
10896/// schema places the `(kind, name, namespace)` reference triple under this
10897/// single container key, so drift on the container axis is exactly as
10898/// load-bearing as drift on the sibling [`FLUX_KIND_GIT_REPOSITORY`]
10899/// (dbbcf29) kind-discriminator + [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
10900/// (7197d38) namespace axes the block nests (a `"source_ref"` / `"source"`
10901/// / `"sourceReference"` / `"gitSourceRef"` typo at either the emit-side
10902/// format-string template or a downstream test-fixture probe silently
10903/// dangles the `HelmRelease.spec.chart.spec.sourceRef` chart resolution +
10904/// the `Kustomization.spec.sourceRef` source resolution at the Flux v2
10905/// source-controller's CRD registration; the source-controller's per-CR
10906/// reconcile loop keys off this exact container axis to source the
10907/// `(kind, name, namespace)` reference triple, and a drift silently freezes
10908/// the dependent per-Servico `dependsOn` chain at apply time with no
10909/// field naming the sourceRef-container-drift root cause).
10910///
10911/// The single source of truth the rendered Flux bundle's per-CR
10912/// source-reference-container-axis-naming reaches for:
10913///
10914///   - the rendered `helmrelease.yaml` document's per-`HelmRelease`
10915///     `spec.chart.spec.sourceRef` block (caixa-flux/src/lib.rs — the
10916///     `cluster_bundle` `helmrelease` format-string template's
10917///     `{source_ref_key}:\n` sub-block header, now threaded through
10918///     the lifted const via a `{source_ref_key}` named-arg
10919///     interpolation);
10920///   - the rendered `kustomization.yaml` document's per-`Kustomization`
10921///     `spec.sourceRef` block (caixa-flux/src/lib.rs — the sibling
10922///     `cluster_bundle` `kustomization` format-string template's
10923///     `{source_ref_key}:\n` sub-block header, now threaded through
10924///     the lifted const via the sibling `{source_ref_key}` named-arg
10925///     interpolation);
10926///   - five test-side navigation sites in `mod tests` that probe the
10927///     rendered documents' `.get("sourceRef")` container axis to pin
10928///     the emitted `(kind, name, namespace)` reference triple against
10929///     the sibling lifted [`FLUX_KIND_GIT_REPOSITORY`] +
10930///     [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] axes.
10931///
10932/// The container-axis key names the same Flux-v2-source-controller-side
10933/// per-CR source-of-truth reference-triple container as the sibling
10934/// per-CRD `kind` discriminator [`FLUX_KIND_GIT_REPOSITORY`] nests inside,
10935/// and must move together on any future Flux v3 rebrand (a hypothetical
10936/// upstream Flux v3 rename of the source-reference container axis from
10937/// `sourceRef` to `source` / `sourceReference` / `sourceOf`, coordinated
10938/// with the upstream fluxcd/flux2 project's per-version deprecation
10939/// cycle, would land at this one const rather than scattered across the
10940/// two per-CR format-string templates + five per-test-fixture probe
10941/// sites).
10942///
10943/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
10944/// "every recurring shape becomes a generator before it becomes a
10945/// pattern; every pattern becomes a library before it becomes
10946/// duplicated code. The duplication budget is zero.") promotes the
10947/// constant to a typed substrate-side `&'static str` on the same
10948/// trajectory the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
10949/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
10950/// [`FLUX_KIND_KUSTOMIZATION`] (2d61a6f) /
10951/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
10952/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
10953/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
10954/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts established on the
10955/// sibling canonical-Flux-v2-load-bearing-string surfaces — extends the
10956/// per-CRD kind-discriminator + apiVersion + install-namespace lift
10957/// trajectory onto the sibling per-CR source-reference container-axis
10958/// key the `cluster_bundle` `HelmRelease` + `Kustomization` renderers
10959/// both consume under their nested `(kind, name, namespace)` reference
10960/// triple.
10961///
10962/// [cf]: ../../caixa_flux/index.html
10963pub const FLUX_KEY_SOURCE_REF: &str = "sourceRef";
10964
10965/// Canonical Flux v2 per-`HelmRelease` inline-chart-template container-axis
10966/// key every `caixa-flux`-emitted `HelmRelease` document nests its per-CR
10967/// chart-template block under (`spec.chart` on `HelmRelease`) — the Flux v2
10968/// CRD schema places the `HelmChartTemplate` sub-document (whose nested
10969/// `spec.chart` string names the referenced chart, `spec.sourceRef` names
10970/// the source-of-truth `(kind, name, namespace)` triple, and
10971/// `spec.interval` names the per-CR reconcile cadence) under this single
10972/// container key, so drift on the container axis silently dangles the
10973/// whole chart-template block the Flux v2 `helm-controller`'s per-CR
10974/// reconcile loop reads to source the referenced chart at Helm-render time
10975/// (a `"Chart"` / `"chartTemplate"` / `"helmChart"` / `"chartRef"` typo at
10976/// either the emit-side format-string template or a downstream test-
10977/// fixture probe silently dangles the `HelmRelease.spec.chart` chart-
10978/// template resolution at the Flux v2 helm-controller's CRD registration;
10979/// the referenced chart never resolves, and the per-Servico workload
10980/// freezes at apply time with no field naming the container-axis-drift
10981/// root cause).
10982///
10983/// The single source of truth the rendered Flux bundle's per-CR
10984/// chart-template-container-axis-naming reaches for:
10985///
10986///   - the rendered `helmrelease.yaml` document's per-`HelmRelease`
10987///     `spec.chart` block (caixa-flux/src/lib.rs — the `cluster_bundle`
10988///     `helmrelease` format-string template's baked `chart:\n` container
10989///     axis at line 914, sibling to the peer lifted [`FLUX_KEY_SOURCE_REF`]
10990///     source-reference container axis nested inside the same block +
10991///     [`FLUX_KEY_VALUES`] per-cluster-override block-body axis at the
10992///     sibling `spec.values` position);
10993///   - two test-side navigation sites in `mod tests` that probe the
10994///     rendered `helmrelease.yaml` document's `.get("chart")` container
10995///     axis to reach the nested `spec.chart.spec.sourceRef.kind` pin
10996///     against the sibling lifted [`FLUX_KIND_GIT_REPOSITORY`] axis
10997///     (caixa-flux/src/lib.rs:2680, 2774).
10998///
10999/// The container-axis key names the same Flux-v2-helm-controller-side
11000/// per-`HelmRelease` chart-template container as the peer sibling per-CR
11001/// source-reference container-axis [`FLUX_KEY_SOURCE_REF`] nests under,
11002/// and must move together on any future Flux v3 rebrand (a hypothetical
11003/// upstream Flux v3 rename of the per-`HelmRelease` chart-template
11004/// container axis from `chart` to `Chart` / `chartTemplate` / `helmChart`
11005/// / `chartRef`, coordinated with the upstream fluxcd/flux2 project's
11006/// per-version deprecation cycle, would land at this one const rather
11007/// than scattered across the one per-CR format-string template + two
11008/// per-test-fixture probe sites).
11009///
11010/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11011/// "every recurring shape becomes a generator before it becomes a
11012/// pattern; every pattern becomes a library before it becomes
11013/// duplicated code. The duplication budget is zero.") promotes the
11014/// constant to a typed substrate-side `&'static str` on the same
11015/// trajectory the [`FLUX_KEY_SOURCE_REF`] (e985089) /
11016/// [`FLUX_KEY_VALUES`] (b54dc87) lifts established on the sibling
11017/// canonical-Flux-v2-per-`HelmRelease`-body-key surfaces — completes the
11018/// triplet of Flux v2 per-`HelmRelease` `spec.*` body-key constants
11019/// (`spec.chart` + `spec.chart.spec.sourceRef` + `spec.values`) the
11020/// `cluster_bundle` renderer's `helmrelease.yaml` format-string template
11021/// threads through its per-CR block-body layout.
11022///
11023/// The inner scalar-value axis `spec.chart.spec.chart` (the chart-name
11024/// leaf the `HelmChartTemplate.spec` sub-document mounts under; the same
11025/// spelling `"chart"` at a distinct schema position) is a schematically
11026/// separate leaf-scalar-key axis (the chart-NAME field the helm-controller
11027/// resolves through the sibling [`FLUX_KEY_SOURCE_REF`] triple's source),
11028/// and is not covered by this lift — a rebrand of the container axis
11029/// (`spec.chart` in this const) does not necessarily coincide with a
11030/// rebrand of the leaf-scalar `spec.chart.spec.chart` chart-name field
11031/// key, so the two axes stay decoupled at the substrate.
11032///
11033/// [cf]: ../../caixa_flux/index.html
11034pub const FLUX_KEY_CHART: &str = "chart";
11035
11036/// Canonical Flux v2 `HelmChartTemplate.spec.chart` per-CR chart-NAME-
11037/// reference leaf-scalar-key every `caixa-flux`-emitted `HelmRelease`
11038/// document nests inside the parent `spec.chart.spec` sub-document (the
11039/// `HelmChartTemplate.spec` block the parent [`FLUX_KEY_CHART`] (8467748)
11040/// container-axis key opens; a nested [`KUBE_KEY_SPEC`] axis inside that
11041/// container hosts this leaf plus its sibling [`FLUX_KEY_SOURCE_REF`]
11042/// per-CR source-reference triple).
11043///
11044/// The parent [`FLUX_KEY_CHART`] docstring explicitly names this leaf-
11045/// scalar axis as *not* covered by that container-axis lift ("The inner
11046/// scalar-value axis `spec.chart.spec.chart` … is a schematically
11047/// separate leaf-scalar-key axis (the chart-NAME field the helm-controller
11048/// resolves through the sibling [`FLUX_KEY_SOURCE_REF`] triple's
11049/// source), and is not covered by this lift — a rebrand of the
11050/// container axis … does not necessarily coincide with a rebrand of
11051/// the leaf-scalar `spec.chart.spec.chart` chart-name field key, so
11052/// the two axes stay decoupled at the substrate."). This const closes
11053/// the substrate-side declaration of the sibling leaf-scalar axis the
11054/// parent container-axis lift explicitly left as future work.
11055///
11056/// The Flux v2 `helm-controller`'s reconcile pipeline reads the chart-
11057/// NAME reference from this exact leaf-scalar-axis key on every
11058/// reconcile: the value at `HelmChartTemplate.spec.chart` names the
11059/// chart-artifact the sibling `HelmChartTemplate.spec.sourceRef`
11060/// triple's source-artifact publishes (an OCIRepository's remote OCI
11061/// chart archive by chart-name, a GitRepository's sub-tree path by
11062/// directory-name, a HelmRepository's chart index entry by chart-name).
11063/// A drifted `spec.chart.spec.Chart` / `spec.chart.spec.chartRef` /
11064/// `spec.chart.spec.chartName` at the emission-side key would silently
11065/// land a well-formed but ignored `HelmChartTemplate.spec.*` extra
11066/// property the apiserver's CRD OpenAPI schema permits (arbitrary
11067/// `spec.*` extras) and the helm-controller would fail to resolve any
11068/// chart-artifact through the sibling `sourceRef` triple's source at
11069/// reconcile time (the sibling `sourceRef` still resolves the *source*
11070/// artifact, but the chart-NAME lookup inside the source
11071/// short-circuits at the missing chart-NAME field with a
11072/// non-self-locating "chart 'unknown' not found in <source>" error far
11073/// from the source `caixa.lisp` / the renderer's format-string
11074/// template).
11075///
11076/// The single source of truth the rendered Flux bundle's per-CR
11077/// `HelmChartTemplate.spec.chart` chart-NAME reference leaf-scalar-
11078/// axis key reaches for:
11079///
11080///   - the rendered `helmrelease.yaml` document's per-`HelmChartTemplate`
11081///     `spec.chart` chart-NAME leaf scalar (caixa-flux/src/lib.rs:1814
11082///     — the `cluster_bundle` `helmrelease` format-string template's
11083///     lifted `chart: {chart_path}` interpolation the peer sibling
11084///     [`FLUX_KEY_SOURCE_REF`] source-reference triple's per-CR source-
11085///     artifact publishes).
11086///
11087/// The leaf-scalar-axis key names the same Flux-v2-helm-controller-
11088/// side per-`HelmChartTemplate` chart-NAME field every
11089/// `caixa-flux`-emitted `HelmRelease` document threads the chart
11090/// artifact name through, and must move together on any future Flux
11091/// v3 rebrand (a hypothetical upstream Flux v3 rename of the per-
11092/// `HelmChartTemplate.spec.chart` chart-NAME reference leaf-scalar-
11093/// axis from `chart` to `Chart` / `chartRef` / `chartName`,
11094/// coordinated with the upstream fluxcd/flux2 project's per-version
11095/// deprecation cycle, would land at this one const rather than
11096/// scattered across the one per-CR format-string template site).
11097///
11098/// Deliberate axis-independence discipline with the parent
11099/// [`FLUX_KEY_CHART`] container-axis re-export: both consts spell the
11100/// same underlying `"chart"` string but name distinct schema axes on
11101/// the same CRD group (Flux v2 `HelmRelease.spec.chart` container-
11102/// axis parent vs `HelmRelease.spec.chart.spec.chart` chart-NAME leaf
11103/// grandchild), so the two `pub const` declarations stay sibling
11104/// constants at the rustc symbol-name axis rather than coalescing onto
11105/// one canonical declaration — a future Flux v3 rebrand on the leaf-
11106/// scalar-axis lands independently of the sibling container-axis
11107/// rebrand. Peer to the deliberate [`CILIUM_KEY_PATH`] (ef6114f) /
11108/// [`GATEWAY_API_KEY_PATH`] (9f45aa4) axis-independence discipline the
11109/// two-CRD-groups-sharing-a-string sibling `"path"` re-exports
11110/// established on the peer canonical-axis-independence surface.
11111///
11112/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11113/// "every recurring shape becomes a generator before it becomes a
11114/// pattern; every pattern becomes a library before it becomes
11115/// duplicated code. The duplication budget is zero.") promotes the
11116/// constant to a typed substrate-side `&'static str` on the same
11117/// trajectory the [`FLUX_KEY_CHART`] (8467748) /
11118/// [`FLUX_KEY_SOURCE_REF`] (e985089) / [`FLUX_KEY_VALUES`] (b54dc87) /
11119/// [`FLUX_KEY_HEALTH_CHECKS`] (6dbff58) lifts established on the
11120/// sibling canonical-Flux-v2-per-`HelmRelease`-body-key surfaces —
11121/// completes the per-`HelmRelease` chart-template `(spec.chart →
11122/// spec.chart.spec.chart + spec.chart.spec.sourceRef)` axis chain by
11123/// declaring the leaf-scalar sibling of the container-axis parent
11124/// the `FLUX_KEY_CHART` lift already anchors.
11125///
11126/// [cf]: ../../caixa_flux/index.html
11127pub const FLUX_HELMCHART_TEMPLATE_KEY_CHART: &str = "chart";
11128
11129/// Canonical Flux v2 per-`HelmRelease` values-override block-body-axis key
11130/// every `caixa-flux`-emitted `HelmRelease` document nests its per-cluster
11131/// value overrides under (`spec.values` on `HelmRelease`) — the Flux v2
11132/// CRD schema places the arbitrary per-cluster-override YAML body under
11133/// this single key, so drift on the block-body-axis silently dangles the
11134/// per-cluster override the `helm-controller`'s per-CR reconcile loop
11135/// merges into the referenced chart's `values.yaml` at Helm-render time
11136/// (a `"Values"` / `"vals"` / `"chartValues"` / `"overrides"` typo at
11137/// either the emit-side format-string template, the `upsert_into_helmrelease_programs`
11138/// upsert-path's `spec.values.programs[]` write, or a downstream
11139/// test-fixture probe silently routes the per-cluster overrides nowhere;
11140/// the workload silently comes up with the referenced chart's admission-
11141/// time defaults, far from the source `caixa.lisp` / the renderer's
11142/// format-string template).
11143///
11144/// The single source of truth every Flux-v2-per-`HelmRelease` values-
11145/// override-block-axis navigation reaches for:
11146///
11147///   - the rendered `helmrelease.yaml` document's per-`HelmRelease`
11148///     `spec.values` block (caixa-flux/src/lib.rs:900 — the
11149///     `cluster_bundle` `helmrelease` format-string template's baked
11150///     `values:\n` key beside the peer sibling lifted
11151///     [`DEFAULT_LIBRARY_NAME`] wrap key + [`HELM_VALUES_KEY_ENABLED`]
11152///     enable-toggle);
11153///   - the `upsert_into_helmrelease_programs` upsert path's
11154///     `spec.values.programs[]` write-side navigation
11155///     (caixa-flux/src/lib.rs:649 — the `lareira-fleet-programs`-
11156///     targeted `HelmRelease` CR's per-Servico entry-list mount);
11157///   - three test-side navigation sites in `mod tests` that probe the
11158///     rendered documents' `.get("values")` block-body axis to pin the
11159///     emitted per-cluster overrides against the sibling lifted
11160///     [`DEFAULT_LIBRARY_NAME`] wrap key + [`HELM_VALUES_KEY_ENABLED`]
11161///     enable-toggle + [`FLEET_PROGRAMS_KEY_PROGRAMS`] entry-list axis.
11162///
11163/// The block-body-axis key names the same Flux-v2-helm-controller-side
11164/// per-`HelmRelease` per-cluster-override block-body every
11165/// `caixa-flux`-emitted `HelmRelease` document threads its per-cluster
11166/// overlays through, and must move together on any future Flux v3
11167/// rebrand (a hypothetical upstream Flux v3 rename of the values-
11168/// override block-body-axis from `values` to `Values` / `chartValues`
11169/// / `overrides`, coordinated with the upstream fluxcd/flux2 project's
11170/// per-version deprecation cycle, would land at this one const rather
11171/// than scattered across the one emit-side format-string template + one
11172/// upsert-side write-side navigation + three per-test-fixture probe
11173/// sites).
11174///
11175/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11176/// "every recurring shape becomes a generator before it becomes a
11177/// pattern; every pattern becomes a library before it becomes
11178/// duplicated code. The duplication budget is zero.") promotes the
11179/// constant to a typed substrate-side `&'static str` on the same
11180/// trajectory the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
11181/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
11182/// [`FLUX_KIND_KUSTOMIZATION`] (2d61a6f) /
11183/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
11184/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
11185/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
11186/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) /
11187/// [`FLUX_KEY_SOURCE_REF`] (e985089) lifts established on the sibling
11188/// canonical-Flux-v2-load-bearing-string surfaces — extends the per-CRD
11189/// kind-discriminator + apiVersion + install-namespace + source-
11190/// reference-container lift trajectory onto the sibling per-CR values-
11191/// override-block-body-axis key both `cluster_bundle` +
11192/// `upsert_into_helmrelease_programs` renderers consume under the
11193/// per-cluster override + per-Servico entry-list nesting.
11194///
11195/// [cf]: ../../caixa_flux/index.html
11196pub const FLUX_KEY_VALUES: &str = "values";
11197
11198/// Canonical Flux v2 per-`Kustomization` health-gate reference-list
11199/// container-axis key every `caixa-flux`-emitted `kustomization.yaml`
11200/// document mounts its per-sibling-`HelmRelease` health-probe list under
11201/// (`spec.healthChecks` on `Kustomization`) — the Flux v2 CRD schema places
11202/// the `[]NamespacedObjectKindReference` list under this single container
11203/// key, so drift on the container axis silently dangles the whole per-
11204/// Kustomization health-gate the Flux v2 `kustomize-controller`'s per-CR
11205/// reconcile loop reads to gate `Ready=True` on the referenced sibling
11206/// `HelmRelease` reaching its `HelmReleaseReady=True` condition (a
11207/// `"HealthChecks"` / `"healthchecks"` / `"healthcheck"` /
11208/// `"health_checks"` / `"probes"` typo at either the emit-side format-
11209/// string template or a downstream test-fixture probe silently
11210/// dangles the parent `Kustomization` at `Reconciling` forever at the Flux
11211/// v2 kustomize-controller's health-gate evaluation; the dependent per-
11212/// cluster fleet-programs upsert chain never sees `Ready=True` at apply
11213/// time with no field naming the container-axis-drift root cause).
11214///
11215/// The single source of truth every Flux-v2-per-`Kustomization` health-
11216/// gate-reference-list-container-axis-naming reaches for:
11217///
11218///   - the rendered `kustomization.yaml` document's per-`Kustomization`
11219///     `spec.healthChecks` block (caixa-flux/src/lib.rs — the
11220///     `cluster_bundle` `kustomization` format-string template's baked
11221///     `healthChecks:\n` container-axis key at line 990, threaded together
11222///     with the sibling lifted [`FLUX_HELMRELEASE_API_VERSION`] per-entry
11223///     `apiVersion` axis + [`FLUX_KIND_HELM_RELEASE`] per-entry `kind`
11224///     axis the health-gate references);
11225///   - three test-side navigation sites in `mod tests` that probe the
11226///     rendered `kustomization.yaml` document's
11227///     `.get("healthChecks")` container axis to pin the emitted per-entry
11228///     `apiVersion` + `kind` against the sibling lifted
11229///     [`FLUX_HELMRELEASE_API_VERSION`] + [`FLUX_KIND_HELM_RELEASE`] axes
11230///     (caixa-flux/src/lib.rs:2266, 2952, 3016).
11231///
11232/// The container-axis key names the same Flux-v2-kustomize-controller-side
11233/// per-`Kustomization` health-gate-reference-list the sibling per-entry
11234/// `apiVersion` [`FLUX_HELMRELEASE_API_VERSION`] + per-entry `kind`
11235/// [`FLUX_KIND_HELM_RELEASE`] axes nest under, and must move together on
11236/// any future Flux v3 rebrand (a hypothetical upstream Flux v3 rename of
11237/// the per-`Kustomization` health-gate reference-list container axis from
11238/// `healthChecks` to `HealthChecks` / `healthchecks` / `healthcheck` /
11239/// `health_checks` / `probes`, coordinated with the upstream fluxcd/flux2
11240/// project's per-version deprecation cycle, would land at this one const
11241/// rather than scattered across the one emit-side format-string template +
11242/// three per-test-fixture probe sites).
11243///
11244/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11245/// "every recurring shape becomes a generator before it becomes a
11246/// pattern; every pattern becomes a library before it becomes
11247/// duplicated code. The duplication budget is zero.") promotes the
11248/// constant to a typed substrate-side `&'static str` on the same
11249/// trajectory the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
11250/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
11251/// [`FLUX_KIND_KUSTOMIZATION`] (2d61a6f) /
11252/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
11253/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
11254/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
11255/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) /
11256/// [`FLUX_KEY_SOURCE_REF`] (e985089) /
11257/// [`FLUX_KEY_CHART`] (8467748) /
11258/// [`FLUX_KEY_VALUES`] (b54dc87) lifts established on the sibling
11259/// canonical-Flux-v2-load-bearing-string surfaces — extends the per-CRD
11260/// kind-discriminator + apiVersion + install-namespace + source-
11261/// reference-container + chart-template-container + values-override-block
11262/// lift trajectory onto the sibling per-`Kustomization` health-gate-
11263/// reference-list container-axis key the `cluster_bundle` renderer
11264/// consumes under its `kustomization.yaml` format-string template.
11265///
11266/// [cf]: ../../caixa_flux/index.html
11267pub const FLUX_KEY_HEALTH_CHECKS: &str = "healthChecks";
11268
11269/// Canonical Flux v2 per-CR reconcile-poll cadence scalar-axis key every
11270/// `caixa-flux`-emitted Flux document (`GitRepository`, `HelmRelease`,
11271/// `Kustomization`) declares its per-CR `spec.interval` reconcile cadence
11272/// under. Unlike the sibling per-CR body-key axes ([`FLUX_KEY_SOURCE_REF`],
11273/// [`FLUX_KEY_CHART`], [`FLUX_KEY_VALUES`], [`FLUX_KEY_HEALTH_CHECKS`])
11274/// which each land on exactly one of the three Flux v2 controller CRDs,
11275/// the reconcile-poll cadence scalar-axis is the *shared* Flux v2 per-CR
11276/// contract every controller (the `source-controller`, the
11277/// `helm-controller`, the `kustomize-controller`) reads to schedule its
11278/// per-CR reconcile loop off the sibling per-CR CRD registration. Drift on
11279/// the scalar-axis key silently drops the per-CR reconcile schedule from
11280/// the Flux v2 controllers' per-CR watch registrations — a `"Interval"` /
11281/// `"period"` / `"cadence"` / `"pollInterval"` / `"reconcileInterval"`
11282/// typo at any of the three emit-side format-string template sites
11283/// silently drops the per-CR reconcile schedule from the affected Flux v2
11284/// controller's per-CR watch registration; the referenced Git source
11285/// never re-polls / the referenced chart never re-templates / the parent
11286/// Kustomization never re-applies at upstream drift, freezing the whole
11287/// cluster's per-`caixa` per-cluster bundle at the last-applied snapshot
11288/// with no field naming the scalar-axis-drift root cause.
11289///
11290/// The single source of truth every Flux-v2-per-CR-reconcile-poll-cadence-
11291/// scalar-axis-naming reaches for — the three per-CR emit sites the
11292/// [`cluster_bundle`][cf] renderer threads through are all named through
11293/// this one const:
11294///
11295///   - the rendered `gitrepository.yaml` document's per-`GitRepository`
11296///     `spec.interval` scalar (caixa-flux/src/lib.rs — the `cluster_bundle`
11297///     `gitrepo` format-string template's baked `interval:` scalar-axis
11298///     key, nested alongside the sibling lifted
11299///     [`FLUX_GITREPOSITORY_API_VERSION`] top-level `apiVersion` +
11300///     [`FLUX_KIND_GIT_REPOSITORY`] top-level `kind` axes the source-
11301///     controller reads to bind the per-CR poll cycle);
11302///   - the rendered `helmrelease.yaml` document's per-`HelmRelease`
11303///     `spec.interval` scalar (caixa-flux/src/lib.rs — the `cluster_bundle`
11304///     `helmrelease` format-string template's baked `interval:` scalar-
11305///     axis key, nested alongside the sibling lifted
11306///     [`FLUX_HELMRELEASE_API_VERSION`] top-level `apiVersion` +
11307///     [`FLUX_KIND_HELM_RELEASE`] top-level `kind` axes the helm-controller
11308///     reads to bind the per-CR poll cycle);
11309///   - the rendered `kustomization.yaml` document's per-`Kustomization`
11310///     `spec.interval` scalar (caixa-flux/src/lib.rs — the `cluster_bundle`
11311///     `kustomization` format-string template's baked `interval:` scalar-
11312///     axis key, nested alongside the sibling lifted
11313///     [`FLUX_KUSTOMIZATION_API_VERSION`] top-level `apiVersion` +
11314///     [`FLUX_KIND_KUSTOMIZATION`] top-level `kind` axes the kustomize-
11315///     controller reads to bind the per-CR poll cycle).
11316///
11317/// The three sites must move together on any future Flux v3 rebrand (a
11318/// hypothetical upstream fluxcd/flux2 rename from `interval` to `Interval`
11319/// / `period` / `cadence` / `pollInterval` / `reconcileInterval`,
11320/// coordinated with the upstream project's per-version deprecation cycle,
11321/// would land at this one const rather than scattered across the three
11322/// per-CR emit-side format-string template sites). This is a distinct
11323/// duplication shape from the sibling [`FLUX_KEY_SOURCE_REF`] /
11324/// [`FLUX_KEY_CHART`] / [`FLUX_KEY_VALUES`] / [`FLUX_KEY_HEALTH_CHECKS`]
11325/// lifts: those closed *one-CR-body-key* duplication trios (one emit-site
11326/// per CR + several test-side probes); this one closes the sibling
11327/// *three-CR-shared-body-key* triplet the Flux v2 reconcile-poll cadence
11328/// contract shares across all three per-cluster-bundle CRDs.
11329///
11330/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11331/// "every recurring shape becomes a generator before it becomes a
11332/// pattern; every pattern becomes a library before it becomes
11333/// duplicated code. The duplication budget is zero.") promotes the
11334/// constant to a typed substrate-side `&'static str` on the same
11335/// trajectory the [`FLUX_KEY_SOURCE_REF`] (e985089) /
11336/// [`FLUX_KEY_CHART`] (8467748) /
11337/// [`FLUX_KEY_VALUES`] (b54dc87) /
11338/// [`FLUX_KEY_HEALTH_CHECKS`] (6dbff58) lifts established on the sibling
11339/// canonical-Flux-v2-per-CR-body-key surfaces — extends the per-CR
11340/// body-key lift trajectory onto the sibling *cross-CR-shared* reconcile-
11341/// poll cadence scalar-axis every Flux v2 controller reads to bind its
11342/// per-CR poll cycle.
11343///
11344/// [cf]: ../../caixa_flux/fn.cluster_bundle.html
11345pub const FLUX_KEY_INTERVAL: &str = "interval";
11346
11347/// Canonical Flux v2 per-`GitRepository` `spec.ref.tag` git-tag-selector
11348/// scalar-axis key every `caixa-flux`-emitted `gitrepository.yaml`
11349/// document declares when the per-Servico bundle's `git_ref` is a
11350/// tag-shaped selector. Peer of [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`]
11351/// / [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] on the sibling per-shape
11352/// arms of the `FluxCD` source-controller `GitRepository.spec.ref`
11353/// ref-selection discriminated-union axis — the three-way sub-selector
11354/// key set the Flux v2 `source-controller` reads to bind the per-CR
11355/// git-source clone `refspec` from the (tag | branch | commit) input
11356/// triple. A drifted value at any of the three keys (`"Tag"` /
11357/// `"gitTag"` / `"tagName"` at this arm, `"Branch"` / `"gitBranch"`
11358/// at the sibling arm, `"Commit"` / `"sha"` / `"revision"` at the
11359/// third arm) silently dangles the whole `spec.ref` sub-block at the
11360/// `FluxCD` `source-controller`'s CRD registration; the per-Servico
11361/// clone never resolves at reconcile time and the sibling
11362/// `HelmRelease.spec.chart.spec.sourceRef` reference dangles at
11363/// admission with no field naming the sub-selector-key-drift root
11364/// cause. Changing this value is a coordinated Flux v3 migration
11365/// alongside the upstream `fluxcd/flux2` deprecation cycle, not an
11366/// incidental edit.
11367///
11368/// The single source of truth every Flux-v2-per-`GitRepository`-
11369/// `spec.ref`-tag-arm-axis-naming reaches for — the two per-render
11370/// consumer sites the [`crate::render`]-side lift closes on the
11371/// [`caixa_flux::GitRefSpec::Tag`] variant are both named through this
11372/// one const via the [`caixa_flux::GitRefSpec::ref_field_name`]
11373/// dispatch:
11374///
11375///   - the rendered `gitrepository.yaml` document's per-`GitRepository`
11376///     `spec.ref.tag` YAML sub-field (caixa-flux's `cluster_bundle`
11377///     `gitref_field` composer, the sole in-tree emission site);
11378///   - the sibling per-render human-readable narrator's `tag <value>`
11379///     prefix (caixa-flux's `cluster_bundle` `tag_human` composer's
11380///     tag-arm branch), the operator-facing per-arm narrator prose
11381///     `feira app graph` / `feira deploy` diagnostics quote.
11382///
11383/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5) —
11384/// promotes the sub-selector-key byte-string to a typed substrate-side
11385/// `&'static str` on the same trajectory the peer per-CR body-key
11386/// [`FLUX_KEY_SOURCE_REF`] (e985089) / [`FLUX_KEY_CHART`] (8467748) /
11387/// [`FLUX_KEY_VALUES`] (b54dc87) / [`FLUX_KEY_HEALTH_CHECKS`] (6dbff58)
11388/// / [`FLUX_KEY_INTERVAL`] (48db6e2) lifts established on the sibling
11389/// canonical-Flux-v2-per-CR-body-key surfaces — pivots the discipline
11390/// from the per-CR body-key axis onto the sibling per-`GitRepository`-
11391/// `spec.ref`-sub-selector-key axis every `cluster_bundle`-rendered
11392/// bundle threads its per-shape ref-selection through, and closes the
11393/// coordinated 2-site duplication (`gitref_field` YAML emit +
11394/// `tag_human` narrator prose) the prior inline `format!("    tag:
11395/// {t:?}")` + `format!("tag {t}")` literals in
11396/// caixa-flux/src/lib.rs carried on the tag-arm of the discriminated-
11397/// union.
11398///
11399/// [cf]: ../../caixa_flux/index.html
11400pub const FLUX_GITREPOSITORY_REF_KEY_TAG: &str = "tag";
11401
11402/// Canonical Flux v2 per-`GitRepository` `spec.ref.branch`
11403/// git-branch-selector scalar-axis key every `caixa-flux`-emitted
11404/// `gitrepository.yaml` document declares when the per-Servico
11405/// bundle's `git_ref` is a branch-shaped selector. Peer of
11406/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
11407/// [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] on the sibling per-shape arms
11408/// of the `FluxCD` source-controller `GitRepository.spec.ref`
11409/// ref-selection discriminated-union axis; see
11410/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] for the full lift rationale.
11411///
11412/// [cf]: ../../caixa_flux/index.html
11413pub const FLUX_GITREPOSITORY_REF_KEY_BRANCH: &str = "branch";
11414
11415/// Canonical Flux v2 per-`GitRepository` `spec.ref.commit`
11416/// git-commit-selector scalar-axis key every `caixa-flux`-emitted
11417/// `gitrepository.yaml` document declares when the per-Servico
11418/// bundle's `git_ref` is a commit-shaped selector. Peer of
11419/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
11420/// [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] on the sibling per-shape arms
11421/// of the `FluxCD` source-controller `GitRepository.spec.ref`
11422/// ref-selection discriminated-union axis; see
11423/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] for the full lift rationale.
11424///
11425/// [cf]: ../../caixa_flux/index.html
11426pub const FLUX_GITREPOSITORY_REF_KEY_COMMIT: &str = "commit";
11427
11428/// Canonical Flux v2 per-`GitRepository` `spec.ref` ref-selection
11429/// discriminated-union parent container-axis key every `caixa-flux`-
11430/// emitted `gitrepository.yaml` document mounts its per-shape
11431/// `{tag, branch, commit}` sub-selector arm under. Nests one level
11432/// above the sibling [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
11433/// [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] /
11434/// [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] triple it wraps — the K8s
11435/// Flux v2 `source.toolkit.fluxcd.io/v1` `GitRepository` CRD schema
11436/// pins the per-CR ref-selection through this `spec.ref` container-
11437/// axis, and every rendered `spec.ref.{tag,branch,commit}` arm the
11438/// [`caixa_flux::GitRefSpec`] discriminated-union emits nests
11439/// beneath this exact key.
11440///
11441/// The FluxCD `source-controller`'s per-CR `RESTMapper` reads
11442/// `spec.ref` to source the per-Servico git clone refspec (the
11443/// container-axis carrying the three-way `{tag, branch, commit}`
11444/// arm the controller dispatches on), so drift on the container-
11445/// axis KEY is exactly as load-bearing as drift on the sibling per-
11446/// shape sub-selector KEY the arms decode through: a `"Ref"` /
11447/// `"gitRef"` / `"revision"` / `"source"` typo at the writer site
11448/// silently emits a `GitRepository` whose ref-selection container-
11449/// axis the CRD schema validator drops as unknown, and the sibling
11450/// `HelmRelease.spec.chart.spec.sourceRef` reference dangles at
11451/// admission with the per-Servico clone never resolving at reconcile
11452/// time — apply-side: the Flux v2 `source-controller`'s per-CR
11453/// reconcile loop no-ops entirely (no clone, no artifact, no
11454/// checksum), the sibling `HelmRelease`'s per-chart resolve step
11455/// finds the empty artifact, and every rendered `HelmRelease` /
11456/// `Kustomization` bundle document downstream of this `GitRepository`
11457/// silently no-ops at the FluxCD apply chain with no field naming
11458/// the container-axis-drift root cause.
11459///
11460/// The single source of truth every Flux-v2-per-`GitRepository`-
11461/// `spec.ref`-container-axis-naming reaches for — the two per-render
11462/// consumer sites the [`crate::render`]-side lift closes:
11463///
11464///   - the rendered `gitrepository.yaml` document's per-`GitRepository`
11465///     `spec.ref` YAML block-body axis (caixa-flux's `cluster_bundle`
11466///     `gitrepo` template composer's `ref:` sub-block header — the
11467///     sole production emission site the prior inline `"ref:"`
11468///     literal sat at);
11469///   - the peer test-fixture navigation site
11470///     (caixa-flux's `cluster_bundle_gitrepository_ref_*` per-arm
11471///     round-trip pin's `.get("ref")` sub-selector traversal step —
11472///     the sole test-side reader site the prior inline `"ref"`
11473///     literal sat at).
11474///
11475/// Changing this value is a coordinated Flux v3 migration alongside
11476/// the upstream `fluxcd/flux2` deprecation cycle, not an incidental
11477/// edit — pinning it here means the migration lands as one edit at
11478/// the const plus a re-run of the pin tests rather than a per-
11479/// renderer sweep with no single source of truth to consult.
11480///
11481/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5)
11482/// promotes the parent-container-axis byte-string to a typed
11483/// substrate-side `&'static str` on the same trajectory the sibling
11484/// per-shape arm sub-selector-key
11485/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] (7d40380) /
11486/// [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] (7d40380) /
11487/// [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] (7d40380) triple lifts
11488/// established on the sibling per-shape arm surface — nests the
11489/// parent container-axis KEY above the already-lifted per-shape arm
11490/// sub-selector-KEY triple, so the whole per-`GitRepository`
11491/// `spec.ref` sub-schema (parent container-axis KEY + per-shape arm
11492/// sub-selector-KEY triple + per-arm value) now navigates through
11493/// four caixa-core `&'static str`s in coordination, and any future
11494/// Flux v2 sub-schema rebrand (an upstream `fluxcd/flux2` v3
11495/// rename of the ref-selection container-axis from `spec.ref` to
11496/// `spec.gitRef` / `spec.source.ref`) lands at one const edit
11497/// coordinated with the sibling per-shape arm lifts.
11498///
11499/// [cf]: ../../caixa_flux/index.html
11500pub const FLUX_GITREPOSITORY_KEY_REF: &str = "ref";
11501
11502/// Canonical Flux v2 `GitRepository.spec.url` per-CR remote-repo-URL
11503/// leaf-scalar-axis key every [`caixa-flux`][cf]-rendered
11504/// `gitrepository.yaml` document declares. The FluxCD `source-controller`
11505/// reads `spec.url` as the git remote URL it clones per-reconcile — the
11506/// authoritative remote the per-Servico artifact archive is sourced from
11507/// at every reconcile cycle. A drifted key (e.g. `"URL"`, `"gitUrl"`,
11508/// `"repo"`, `"repository"`) at the writer site would silently emit a
11509/// `GitRepository` whose CRD schema validator drops the URL field as
11510/// unknown, and the per-Servico artifact would never populate — the
11511/// downstream `HelmRelease.spec.chart.spec.sourceRef` reference dangles
11512/// with an empty artifact at admission, every rendered `HelmRelease` /
11513/// `Kustomization` bundle document downstream silently no-ops at
11514/// reconcile time with no field naming the URL-key-drift root cause.
11515///
11516/// Sibling to the already-lifted per-`GitRepository`-CR `spec` sub-
11517/// block keys [`FLUX_GITREPOSITORY_KEY_REF`] (84a3c20, the parent
11518/// container-axis for the `spec.ref.{tag,branch,commit}` per-shape arm
11519/// discriminated union) — this constant names the peer per-CR leaf-
11520/// scalar remote-URL axis on the same top-level `spec` position. Both
11521/// axes together completely enumerate the `GitRepository.spec.*` per-
11522/// CR sub-block keys `caixa-flux`'s current `cluster_bundle` gitrepo
11523/// template writes (`spec.interval` reaches through the lifted
11524/// `FLUX_KEY_INTERVAL`, `spec.url` through this constant, `spec.ref`
11525/// through [`FLUX_GITREPOSITORY_KEY_REF`]), so any future Flux v3
11526/// `GitRepository` schema promotion lands as one caixa-core edit
11527/// coordinated across the sibling sub-block key axes.
11528///
11529/// The single source of truth every Flux-v2-per-`GitRepository`-
11530/// `spec.url`-leaf-scalar-axis-naming reaches for — one production
11531/// consumer today:
11532///
11533///   - the rendered `gitrepository.yaml` document's per-`GitRepository`
11534///     `spec.url` leaf-scalar remote-URL axis (caixa-flux's
11535///     `cluster_bundle` `gitrepo` template composer's `url:` sub-key
11536///     — the sole production emission site the prior inline `"url:"`
11537///     literal sat at).
11538///
11539/// Every future per-`GitRepository` renderer (the M4 typed-Aplicacao
11540/// materializer's per-Aplicacao `GitRepository` synthesis for
11541/// per-aggregator-manifest sources, any future `caixa-otel`
11542/// collector-pipeline `GitRepository`, any future per-cluster snapshot
11543/// `GitRepository` the operator emits) inherits the canonical URL
11544/// leaf-scalar key by construction with no opportunity for
11545/// per-renderer drift.
11546///
11547/// [cf]: ../../caixa_flux/index.html
11548pub const FLUX_GITREPOSITORY_KEY_URL: &str = "url";
11549
11550/// Canonical Flux v2 per-cluster-bundle `HelmRelease` document
11551/// filename every [`caixa-flux`][cf]-rendered `cluster_bundle` carries
11552/// at the per-Servico bundle's rendered file collection — the fixed
11553/// filename the sibling `gitrepository.yaml` + `kustomization.yaml`
11554/// bundle documents key against when the cluster-side `FluxCD`
11555/// controllers reconcile the per-Servico release cycle, and the
11556/// exact filename every downstream consumer that reaches into the
11557/// rendered bundle by document name looks up.
11558///
11559/// Two production consumers reach for this filename:
11560///
11561///   - [`caixa-flux`][cf]'s [`cluster_bundle`][cb] `BundleFile`
11562///     assembly's per-file `path` axis for the `HelmRelease`
11563///     document — the sole caixa-flux production emit site the prior
11564///     inline `PathBuf::from("helmrelease.yaml")` literal sat at,
11565///     one of the three canonical per-Servico Flux bundle files the
11566///     renderer emits alongside the sibling `gitrepository.yaml` +
11567///     `kustomization.yaml` documents;
11568///   - the peer test-fixture navigators in this crate reach into the
11569///     rendered `BundleFile` collection by the same filename to
11570///     round-trip-pin each emitted `HelmRelease` axis — a dozen
11571///     `.find(|f| f.path == PathBuf::from("helmrelease.yaml"))` +
11572///     `names.contains(&"helmrelease.yaml".to_string())` fixture
11573///     navigators across every per-CR body-axis sweep, `apiVersion`
11574///     round-trip, `spec.chart` / `spec.values` / `spec.sourceRef`
11575///     nested block existence pin.
11576///
11577/// Until this lift landed the filename `"helmrelease.yaml"` lived as
11578/// thirteen verbatim inline literals (one production
11579/// `PathBuf::from("helmrelease.yaml")` at the `cluster_bundle`
11580/// `BundleFile`-vec construction site + twelve test-side
11581/// `PathBuf::from("helmrelease.yaml")` /
11582/// `names.contains(&"helmrelease.yaml".to_string())` /
11583/// `.expect("helmrelease.yaml present")` fixture navigators). A drift
11584/// on the emit side (a `"HelmRelease.yaml"` / `"helm-release.yaml"` /
11585/// `"helmrelease.yml"` / `"helm_release.yaml"` typo, or an accidental
11586/// per-fork rebrand onto a stale filename any per-edition Flux
11587/// substrate might introduce) at any one site would surface as one of
11588/// two silent failure modes at cluster-side reconcile time:
11589///
11590///   - the `FluxCD` `kustomize-controller` refuses to apply the
11591///     rendered bundle at all — the per-Servico
11592///     `Kustomization.spec.path` opens the bundle directory and its
11593///     `HelmRelease` navigator returns `None`, with the reconcile
11594///     dropping at "no `HelmRelease` document found under this
11595///     bundle" far from the emit-drift commit's source, and the
11596///     per-Servico release cycle drops with no field naming the
11597///     bundle-filename-drift root cause (the operator sees "the
11598///     release never picks up its Helm chart" with no canonical
11599///     anchor to compare the rendered filename against);
11600///   - the sibling `Kustomization` document's per-CR
11601///     `spec.healthChecks[]` references the drifted filename via
11602///     `namespace/name` — the healthCheck stays perpetually `Unknown`
11603///     because the referenced `HelmRelease` never materializes at the
11604///     expected bundle path, and the peer `GitRepository` document's
11605///     every-poll reconcile ticks the bundle-tree hash over the
11606///     drifted filename with the per-Servico release cycle silently
11607///     frozen at "waiting on healthCheck".
11608///
11609/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11610/// "every recurring shape becomes a generator before it becomes a
11611/// pattern; every pattern becomes a library before it becomes
11612/// duplicated code. The duplication budget is zero.") promotes the
11613/// filename to a typed substrate-side `&'static str` on the same
11614/// trajectory the peer [`HELM_CHART_YAML_FILENAME`] (c2c99b0) /
11615/// [`HELM_VALUES_YAML_FILENAME`] (9a980ba) lifts established on the
11616/// sibling Helm-chart-directory filename axes — pivots the
11617/// canonical-filename single-sourcing discipline from the per-Helm-
11618/// chart-directory metadata / values file surfaces onto the sibling
11619/// per-Flux-v2-bundle `HelmRelease` document filename axis every
11620/// rendered per-Servico bundle declares at its cluster-side reconcile
11621/// tree. Peer of a future sibling lift on the other two per-Servico
11622/// Flux bundle document filenames (`gitrepository.yaml` +
11623/// `kustomization.yaml`) — this const anchors the first coordinate
11624/// of the per-bundle
11625/// `(gitrepository, helmrelease, kustomization)` filename axis triple
11626/// every rendered cluster bundle carries.
11627///
11628/// [cf]: ../../caixa_flux/index.html
11629/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
11630pub const FLUX_HELMRELEASE_YAML_FILENAME: &str = "helmrelease.yaml";
11631
11632/// Canonical Flux v2 per-cluster-bundle `GitRepository` document
11633/// filename every [`caixa-flux`][cf]-rendered [`cluster_bundle`][cb]
11634/// carries at the per-Servico bundle's rendered file collection — the
11635/// fixed filename the sibling `helmrelease.yaml` +
11636/// `kustomization.yaml` documents key against when the cluster-side
11637/// `FluxCD` `source-controller` reconciles the per-Servico Git-source
11638/// poll cycle, and the exact filename every downstream consumer that
11639/// reaches into the rendered bundle by document name looks up.
11640///
11641/// Two production consumers reach for this filename:
11642///
11643///   - [`caixa-flux`][cf]'s [`cluster_bundle`][cb] `BundleFile`
11644///     assembly's per-file `path` axis for the `GitRepository`
11645///     document — the sole caixa-flux production emit site the prior
11646///     inline `PathBuf::from("gitrepository.yaml")` literal sat at,
11647///     one of the three canonical per-Servico Flux bundle files the
11648///     renderer emits alongside the sibling `helmrelease.yaml` +
11649///     `kustomization.yaml` documents (the second coordinate of the
11650///     per-bundle `(gitrepository, helmrelease, kustomization)`
11651///     filename axis triple this const closes);
11652///   - the peer test-fixture navigators in this crate reach into the
11653///     rendered `BundleFile` collection by the same filename to
11654///     round-trip-pin each emitted `GitRepository` axis — every
11655///     `.find(|f| f.path == PathBuf::from("gitrepository.yaml"))` +
11656///     `names.contains(&"gitrepository.yaml".to_string())` fixture
11657///     navigator across the per-CR body-axis sweeps that pin the
11658///     Git-source apiVersion / kind / `spec.url` / `spec.ref`
11659///     round-trips.
11660///
11661/// Until this lift landed the filename `"gitrepository.yaml"` lived
11662/// as nine verbatim inline literals across [`caixa-flux`][cf] (one
11663/// production `PathBuf::from("gitrepository.yaml")` at the
11664/// `cluster_bundle` `BundleFile`-vec construction site + eight
11665/// test-side fixture navigators). A drift on the emit side (a
11666/// `"GitRepository.yaml"` / `"git-repository.yaml"` /
11667/// `"gitrepository.yml"` typo, or an accidental per-fork rebrand)
11668/// would surface at cluster-side reconcile time far from the source:
11669/// the `FluxCD` `source-controller` never registers a `GitRepository`
11670/// document under the expected bundle path, the sibling
11671/// `HelmRelease.spec.chart.spec.sourceRef` reference dangles at
11672/// admission, and the per-Servico release cycle silently freezes at
11673/// last-applied state with no field naming the filename-drift root
11674/// cause.
11675///
11676/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11677/// "every recurring shape becomes a generator before it becomes a
11678/// pattern; every pattern becomes a library before it becomes
11679/// duplicated code. The duplication budget is zero.") promotes the
11680/// filename to a typed substrate-side `&'static str` on the same
11681/// trajectory the peer [`FLUX_HELMRELEASE_YAML_FILENAME`] (ba7b0b2) /
11682/// [`HELM_CHART_YAML_FILENAME`] (c2c99b0) /
11683/// [`HELM_VALUES_YAML_FILENAME`] (9a980ba) lifts established on the
11684/// sibling per-Flux-v2-bundle / per-Helm-chart-directory filename
11685/// axes — pairs with the sibling
11686/// [`FLUX_KUSTOMIZATION_YAML_FILENAME`] on the third coordinate to
11687/// close the per-bundle `(gitrepository, helmrelease, kustomization)`
11688/// filename axis triple every rendered cluster bundle carries.
11689///
11690/// [cf]: ../../caixa_flux/index.html
11691/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
11692pub const FLUX_GITREPOSITORY_YAML_FILENAME: &str = "gitrepository.yaml";
11693
11694/// Canonical Flux v2 per-cluster-bundle `Kustomization` document
11695/// filename every [`caixa-flux`][cf]-rendered [`cluster_bundle`][cb]
11696/// carries at the per-Servico bundle's rendered file collection — the
11697/// fixed filename the sibling `gitrepository.yaml` +
11698/// `helmrelease.yaml` documents key against when the cluster-side
11699/// `FluxCD` `kustomize-controller` reconciles the per-Servico apply
11700/// cycle, and the exact filename every downstream consumer that
11701/// reaches into the rendered bundle by document name looks up.
11702///
11703/// Two production consumers reach for this filename:
11704///
11705///   - [`caixa-flux`][cf]'s [`cluster_bundle`][cb] `BundleFile`
11706///     assembly's per-file `path` axis for the `Kustomization`
11707///     document — the sole caixa-flux production emit site the prior
11708///     inline `PathBuf::from("kustomization.yaml")` literal sat at,
11709///     one of the three canonical per-Servico Flux bundle files the
11710///     renderer emits alongside the sibling `gitrepository.yaml` +
11711///     `helmrelease.yaml` documents (the third coordinate of the
11712///     per-bundle `(gitrepository, helmrelease, kustomization)`
11713///     filename axis triple this const closes);
11714///   - the peer test-fixture navigators in this crate reach into the
11715///     rendered `BundleFile` collection by the same filename to
11716///     round-trip-pin each emitted `Kustomization` axis — every
11717///     `.find(|f| f.path == PathBuf::from("kustomization.yaml"))` +
11718///     `names.contains(&"kustomization.yaml".to_string())` fixture
11719///     navigator across the per-CR body-axis sweeps that pin the
11720///     Kustomization apiVersion / kind / `spec.sourceRef` /
11721///     `spec.healthChecks` round-trips.
11722///
11723/// Until this lift landed the filename `"kustomization.yaml"` lived
11724/// as sixteen verbatim inline literals across [`caixa-flux`][cf]
11725/// (one production `PathBuf::from("kustomization.yaml")` at the
11726/// `cluster_bundle` `BundleFile`-vec construction site + fifteen
11727/// test-side fixture navigators). A drift on the emit side (a
11728/// `"Kustomization.yaml"` / `"kustomize.yaml"` / `"kustomization.yml"`
11729/// typo, or an accidental per-fork rebrand) would surface at
11730/// cluster-side reconcile time far from the source: the `FluxCD`
11731/// `kustomize-controller` never picks up the parent `Kustomization`
11732/// under the expected bundle path, every per-Servico apply silently
11733/// stops advancing at last-applied state, and the sibling
11734/// `HelmRelease` / `GitRepository` reconciles register with no
11735/// parent Kustomization gating their health, with no field naming
11736/// the filename-drift root cause.
11737///
11738/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11739/// "every recurring shape becomes a generator before it becomes a
11740/// pattern; every pattern becomes a library before it becomes
11741/// duplicated code. The duplication budget is zero.") promotes the
11742/// filename to a typed substrate-side `&'static str` on the same
11743/// trajectory the peer [`FLUX_HELMRELEASE_YAML_FILENAME`] (ba7b0b2) /
11744/// [`FLUX_GITREPOSITORY_YAML_FILENAME`] (this commit) /
11745/// [`HELM_CHART_YAML_FILENAME`] (c2c99b0) /
11746/// [`HELM_VALUES_YAML_FILENAME`] (9a980ba) lifts established on the
11747/// sibling per-Flux-v2-bundle / per-Helm-chart-directory filename
11748/// axes — closes the per-bundle `(gitrepository, helmrelease,
11749/// kustomization)` filename axis triple every rendered cluster
11750/// bundle carries.
11751///
11752/// [cf]: ../../caixa_flux/index.html
11753/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
11754pub const FLUX_KUSTOMIZATION_YAML_FILENAME: &str = "kustomization.yaml";
11755
11756/// Canonical K8s Gateway API CRD `apiVersion` every `caixa-mesh`-emitted
11757/// `Gateway` / `HTTPRoute` document declares. The K8s apiserver-side
11758/// SIG-Network Gateway API conformance registers the `Gateway` /
11759/// `HTTPRoute` / `GatewayClass` / `TCPRoute` / `TLSRoute` / `GRPCRoute`
11760/// CRDs at this exact group/version (`gateway.networking.k8s.io/v1`);
11761/// drift to a stale `v1beta1` / `v1alpha2` (the pre-GA Gateway API betas
11762/// every upstream conformance doc names) silently routes the rendered
11763/// `Gateway` / `HTTPRoute` outside the apiserver's CRD-version
11764/// registration and breaks at apply time with a non-self-locating "no
11765/// kind 'Gateway' is registered for version
11766/// 'gateway.networking.k8s.io/v1beta1'" error far from the source
11767/// caixa.lisp / the renderer's [`kube_resource_skeleton`] call site.
11768///
11769/// The single source of truth both Gateway-API CRD axes of the rendered
11770/// Aplicacao mesh bundle reach for:
11771///
11772///   - `Gateway` `apiVersion` — the top-level CRD-group/version the
11773///     rendered Gateway document declares (caixa-mesh/src/lib.rs:455 —
11774///     the `gateway_routes` per-Aplicacao Gateway skeleton call);
11775///   - `HTTPRoute` `apiVersion` — the same Gateway API CRD
11776///     group/version every per-`:entrada :paths` HTTPRoute declares
11777///     (caixa-mesh/src/lib.rs:496 — the `gateway_routes` HTTPRoute
11778///     skeleton call). The K8s SIG-Network Gateway API contract bumps
11779///     `Gateway`, `HTTPRoute`, `GatewayClass`, and the rest of the
11780///     per-conformance CRD set as a unit; a future Gateway-API GA
11781///     promotion (the upstream Gateway API SIG roadmap names per-CRD-
11782///     group / per-version migration once the v1 GA branch matures) on
11783///     one axis without a coordinated edit on the other would have
11784///     silently emitted a `Gateway` / `HTTPRoute` pair pointing at
11785///     distinct CRD versions — apply-side: the `Gateway` and
11786///     `HTTPRoute` land in two distinct apiserver-side CRD
11787///     registrations, the per-route attached-policy resolution
11788///     pipeline never binds, every external `:entrada` flow drops at
11789///     the gateway with no field naming the version-drift root cause.
11790///
11791/// Until this lift landed both axes carried inline
11792/// `gateway.networking.k8s.io/v1` literals across two production-code
11793/// occurrences in caixa-mesh/src/lib.rs:455, 496 (the `gateway_routes`
11794/// `Gateway` + `HTTPRoute` skeleton calls) plus a matching pair inside
11795/// the in-file `gateway_carries_canonical_kube_skeleton_without_labels`
11796/// + `httproute_carries_canonical_kube_skeleton_without_labels` test
11797/// fixtures — four occurrences of the same load-bearing Gateway API
11798/// CRD-group/version convention, drift-prone by construction.
11799///
11800/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11801/// "every recurring shape becomes a generator before it becomes a
11802/// pattern; every pattern becomes a library before it becomes
11803/// duplicated code. The duplication budget is zero.") promotes the
11804/// constant to a typed substrate-side `&'static str` on the same
11805/// trajectory the [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
11806/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
11807/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
11808/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts established on
11809/// the peer Flux-v2-controller-triplet canonical-load-bearing-string
11810/// axis — extends the discipline from the cluster-side Flux v2
11811/// reconcile contract (the source/helm/kustomize controllers) onto
11812/// the cluster-side K8s Gateway API ingress contract (the
11813/// Gateway-API-conformant gateway implementation: Cilium, Istio,
11814/// Envoy Gateway, NGINX, et al.). The two render-side consumers now
11815/// thread the same `&'static str` through their `kube_resource_skeleton`
11816/// calls so a future Gateway API CRD-group/version promotion lands in
11817/// one place; every future renderer that reaches for the canonical
11818/// Gateway API CRD apiVersion (the future M4
11819/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
11820/// Gateway + HTTPRoute, a future per-edge `TCPRoute` / `TLSRoute` /
11821/// `GRPCRoute` the caixa-mesh emits for non-HTTP `:entrada` edges,
11822/// a future `GatewayClass` the operator emits for per-cluster
11823/// gateway-class scoping) inherits the same value by construction
11824/// with no opportunity for per-renderer drift.
11825///
11826/// [cm]: ../../caixa_mesh/index.html
11827pub const GATEWAY_API_API_VERSION: &str = "gateway.networking.k8s.io/v1";
11828
11829/// Canonical Cilium CRD `apiVersion` every `caixa-mesh`-emitted
11830/// `CiliumNetworkPolicy` document declares. The Cilium control plane's
11831/// upstream-shipped CRD bundle registers `CiliumNetworkPolicy`,
11832/// `CiliumClusterwideNetworkPolicy`, `CiliumEndpoint`, `CiliumIdentity`,
11833/// `CiliumNode`, `CiliumLocalRedirectPolicy`, and the rest of the
11834/// per-conformance Cilium CRD set at this exact group/version
11835/// (`cilium.io/v2`); drift to a stale `v2alpha1` (the historical
11836/// pre-stable Cilium-CRD-group/version label upstream Cilium-CRD docs
11837/// reference for in-flight per-CRD-version migration) silently routes
11838/// the rendered `CiliumNetworkPolicy` outside the cluster's
11839/// Cilium-operator-side CRD-version registration and breaks at apply
11840/// time with a non-self-locating "no kind 'CiliumNetworkPolicy' is
11841/// registered for version 'cilium.io/v2alpha1'" error far from the
11842/// source caixa.lisp / the renderer's [`kube_resource_skeleton`] call
11843/// site.
11844///
11845/// The single source of truth the rendered Aplicacao Cilium-side
11846/// mesh bundle's CRD-group/version axis reaches for:
11847///
11848///   - `CiliumNetworkPolicy` `apiVersion` — the top-level CRD-group/
11849///     version every emitted CNP document declares
11850///     (caixa-mesh/src/lib.rs:326 — the `cilium_network_policies`
11851///     per-`(:de, :para)` policy skeleton call). Until this lift
11852///     landed both the production-code emit at the per-policy
11853///     skeleton call site and the matching in-file
11854///     `cilium_policy_carries_canonical_kube_skeleton` test fixture
11855///     pin (caixa-mesh/src/lib.rs:1560) carried inline `"cilium.io/v2"`
11856///     string literals — two occurrences of the same load-bearing
11857///     Cilium-CRD-group/version convention, drift-prone by
11858///     construction. The Cilium project bumps the per-conformance
11859///     Cilium-CRD set as a unit; a future Cilium-CRD-group/version
11860///     promotion (the upstream Cilium roadmap names per-CRD-group /
11861///     per-version migration once the `cilium.io/v3` branch lands) on
11862///     one axis without a coordinated edit on the other would have
11863///     silently emitted a `CiliumNetworkPolicy` document whose
11864///     top-level apiVersion drifts off the lifted-test-fixture pin —
11865///     apply-side: the policy lands in a stale CRD-version
11866///     registration the Cilium operator no longer watches, every
11867///     `(:de, :para)` intra-mesh L4 contract drops at the eBPF data
11868///     plane with no field naming the version-drift root cause.
11869///
11870/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11871/// "every recurring shape becomes a generator before it becomes a
11872/// pattern; every pattern becomes a library before it becomes
11873/// duplicated code. The duplication budget is zero.") promotes the
11874/// constant to a typed substrate-side `&'static str` on the same
11875/// trajectory the [`GATEWAY_API_API_VERSION`] (3c6cfc3) /
11876/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
11877/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
11878/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
11879/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts established on
11880/// the peer K8s Gateway API ingress / Flux v2 reconcile canonical-
11881/// load-bearing-string axes — extends the discipline from the
11882/// cluster-side K8s Gateway API ingress + Flux v2 reconcile contracts
11883/// onto the cluster-side Cilium identity-based mesh contract (the
11884/// eBPF-anchored Cilium control plane that materializes every
11885/// per-`(:de, :para)` L4 / L7 contrato as an identity-keyed eBPF
11886/// allow rule). The render-side consumer now threads the same
11887/// `&'static str` through its `kube_resource_skeleton` call so a
11888/// future Cilium-CRD-group/version promotion lands in one place;
11889/// every future renderer that reaches for the canonical
11890/// Cilium-CRD apiVersion (the future M4
11891/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
11892/// per-Aplicacao CiliumNetworkPolicy fan-out, a future
11893/// `CiliumClusterwideNetworkPolicy` the caixa-mesh emits for
11894/// cluster-scoped baseline-allow / baseline-deny rules, a future
11895/// `CiliumLocalRedirectPolicy` the operator emits for per-Servico
11896/// local-redirect coordination) inherits the same value by
11897/// construction with no opportunity for per-renderer drift.
11898///
11899/// [cm]: ../../caixa_mesh/index.html
11900pub const CILIUM_API_VERSION: &str = "cilium.io/v2";
11901
11902/// Canonical Cilium CRD `kind` discriminator the rendered
11903/// `CiliumNetworkPolicy` document declares at its top-level
11904/// [`KUBE_KEY_KIND`] axis. Pairs with the sibling [`CILIUM_API_VERSION`]
11905/// (279d611) — the K8s apiserver-side CRD resolution contract is the
11906/// `(apiVersion, kind)` tuple keyed against the registered
11907/// `CustomResourceDefinition`, so drift on the kind axis is exactly as
11908/// load-bearing as drift on the apiVersion axis it accompanies (the
11909/// apiserver's `RESTMapper` consults both together; a
11910/// `("cilium.io/v2", "CilumNetworkPolicy")` typo at the production-code
11911/// call site lands outside the registered Cilium-operator-side
11912/// `CiliumNetworkPolicy` CRD's `RESTKind` lookup, surfacing apply-side as
11913/// a non-self-locating "no kind 'CilumNetworkPolicy' is registered for
11914/// version 'cilium.io/v2'" error far from the source caixa.lisp / the
11915/// renderer's [`kube_resource_skeleton`] call site).
11916///
11917/// The single source of truth the rendered Aplicacao Cilium-side mesh
11918/// bundle's `CiliumNetworkPolicy`-naming axis reaches for:
11919///
11920///   - the rendered `CiliumNetworkPolicy` document's top-level
11921///     [`KUBE_KEY_KIND`] axis (caixa-mesh/src/lib.rs:382 — the
11922///     `cilium_network_policies` per-`(:de, :para)` policy
11923///     [`kube_resource_skeleton`] call).
11924///
11925/// The kind axis names the same Cilium-operator-side CRD discriminator
11926/// as the sibling [`CILIUM_API_VERSION`] apiVersion axis and must move
11927/// together on any future `cilium.io/v3` rebrand. Until this lift
11928/// landed the axis carried an inline `CiliumNetworkPolicy` literal at
11929/// the one production-code occurrence in caixa-mesh/src/lib.rs:382 (the
11930/// `cilium_network_policies` [`kube_resource_skeleton`] kind argument)
11931/// plus a matching set inside the in-file
11932/// `cilium_policy_carries_canonical_kube_skeleton` /
11933/// `render_all_includes_every_artifact_kind` /
11934/// `cilium_policy_metadata_block_iterates_alphabetically` test fixtures
11935/// — occurrences of the same load-bearing Cilium-CRD-`kind`-discriminator
11936/// convention, drift-prone by construction. A drift on the top-level
11937/// `CiliumNetworkPolicy` `kind` axis would have surfaced as a
11938/// non-self-locating "no kind 'CilumNetworkPolicy' is registered for
11939/// version 'cilium.io/v2'" error far from the source caixa.lisp at
11940/// apply parse time, with the rendered per-`(:de, :para)` CNP never
11941/// landing in the Cilium-operator-side CRD registration and every
11942/// intra-mesh L4/L7 contrato flow dropping at the eBPF data plane with
11943/// no field naming the kind-discriminator-drift root cause.
11944///
11945/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
11946/// "every recurring shape becomes a generator before it becomes a
11947/// pattern; every pattern becomes a library before it becomes
11948/// duplicated code. The duplication budget is zero.") promotes the
11949/// constant to a typed substrate-side `&'static str` on the same
11950/// trajectory the [`FLUX_KIND_KUSTOMIZATION`] (4114773) /
11951/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
11952/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
11953/// [`CILIUM_API_VERSION`] (279d611) /
11954/// [`GATEWAY_API_API_VERSION`] (3c6cfc3) lifts established on the
11955/// sibling cluster-side-CRD-`kind`-discriminator + canonical-CRD-
11956/// group/version axes — extends the discipline from the apiVersion
11957/// half of the `(apiVersion, kind)` CRD-lookup tuple onto the kind
11958/// half on the same Cilium-CRD-axis, completing the per-Cilium-CRD
11959/// kind+apiVersion lift pair the M3 Aplicacao mesh renderer's eBPF
11960/// data-plane contract rests on. The render-side consumer now threads
11961/// the same `&'static str` through its [`kube_resource_skeleton`] call
11962/// so a future `cilium.io/v3` rebrand lands in one place; every future
11963/// renderer that reaches for the canonical Cilium `CiliumNetworkPolicy`
11964/// kind (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
11965/// materializer's per-Aplicacao CiliumNetworkPolicy fan-out, a future
11966/// per-cluster baseline-allow / baseline-deny renderer that emits the
11967/// peer `CiliumClusterwideNetworkPolicy`, a future per-Servico
11968/// local-redirect renderer that emits the peer
11969/// `CiliumLocalRedirectPolicy`) inherits the same value by construction
11970/// with no opportunity for per-renderer drift.
11971///
11972/// Same "the typed constant lives in one place" discipline the
11973/// [`FLUX_KIND_KUSTOMIZATION`] (4114773) /
11974/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
11975/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
11976/// [`CILIUM_API_VERSION`] (279d611) /
11977/// [`GATEWAY_API_API_VERSION`] (3c6cfc3) /
11978/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts apply on the peer
11979/// canonical-cluster-side-CRD-discriminator surface.
11980///
11981/// [cm]: ../../caixa_mesh/index.html
11982pub const CILIUM_KIND_NETWORK_POLICY: &str = "CiliumNetworkPolicy";
11983
11984/// Canonical Cilium `CiliumNetworkPolicy` L4/L7 per-ingress-rule port-set
11985/// container-axis key every `cilium_network_policies`-emitted CNP
11986/// document mounts its per-ingress-rule `[{ports: […], rules: {…}}]`
11987/// list under (`spec.ingress[].toPorts[]`). Pairs with the sibling
11988/// [`KUBE_KEY_RULES`] (a205eb3) — the Cilium L7-dispatch schema nests
11989/// `spec.ingress[].toPorts[].rules.http[]` under the shared
11990/// (`toPorts`, `rules`) container-key pair, so drift on the `toPorts`
11991/// axis is exactly as load-bearing as drift on the `rules` axis it
11992/// wraps (the Cilium-operator-side CRD schema validator drops any
11993/// `spec.ingress[]` entry whose port-set container carries an
11994/// unrecognized key — a `"toports"` / `"toPort"` / `"targetPorts"` typo
11995/// silently emits an ingress rule whose per-port set the Cilium
11996/// operator's per-CNP L4/L7 dispatch pass no-ops entirely: every
11997/// intra-mesh `:contratos` flow the CNP was authored to allow now
11998/// drops at the eBPF data plane's default-deny gate with no field
11999/// naming the port-set-container-drift root cause).
12000///
12001/// The single source of truth the rendered Aplicacao Cilium-side mesh
12002/// bundle's per-CNP port-set-container-naming axis reaches for:
12003///
12004///   - the rendered `CiliumNetworkPolicy` document's
12005///     `spec.ingress[].toPorts[]` axis (caixa-mesh/src/lib.rs:939 —
12006///     the `cilium_network_policies` per-`(:de, :para)` policy's
12007///     `ingress_rule.insert("toPorts", …)` call).
12008///
12009/// The port-set-container axis names the same Cilium-operator-side
12010/// per-ingress-rule dispatch container as the sibling [`KUBE_KEY_RULES`]
12011/// nested L7-dispatch container axis and must move together on any
12012/// future Cilium CRD schema rebrand (an upstream `cilium.io/v3` rename
12013/// of the port-set container from `toPorts` to `ports` / `portSet` /
12014/// `endpoints`, coordinated with the Cilium project's periodic CRD
12015/// schema-migration passes). Until this lift landed the axis carried
12016/// an inline `toPorts` literal at the one production-code occurrence
12017/// in caixa-mesh/src/lib.rs:939 (the `cilium_network_policies`
12018/// `ingress_rule.insert("toPorts", …)` call) plus a matching set
12019/// inside the in-file `cilium_http_contracts_emit_l7_rules` /
12020/// `cilium_pubsub_contracts_skip_l7_rules` /
12021/// `cilium_multiple_edges_same_pair_fold_into_one_policy` /
12022/// `cnp_authentication_carries_mtls_overlay_at_ingress_rule_level` /
12023/// `cnp_l4_fallback_port_routes_through_lifted_default_servico_port`
12024/// test-fixture navigations — six occurrences of the same load-bearing
12025/// Cilium-CRD-`toPorts`-container-key convention, drift-prone by
12026/// construction. A drift on any one production or test-fixture site
12027/// to `"toports"` / `"toPort"` / `"targetPorts"` would have surfaced
12028/// as a Cilium-operator-side schema validator drop at apply time (the
12029/// affected `spec.ingress[]` entry's port-set container the CRD
12030/// schema validator recognizes as unknown), with every intra-mesh
12031/// `:contratos` flow the CNP was authored to allow dropping at the
12032/// eBPF data plane's default-deny gate with no field naming the
12033/// container-drift root cause. A drift on the test-fixture side
12034/// silently masks the emission-side pin (`.get("toPorts")` returns
12035/// `None` under both the drifted-key emitter and the drifted-key
12036/// probe — the `cilium_pubsub_contracts_skip_l7_rules` absence pin's
12037/// downstream `to_ports.get("rules").is_none()` assertion succeeds
12038/// vacuously because `to_ports` is itself `None`).
12039///
12040/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12041/// "every recurring shape becomes a generator before it becomes a
12042/// pattern; every pattern becomes a library before it becomes
12043/// duplicated code. The duplication budget is zero.") promotes the
12044/// constant to a typed substrate-side `&'static str` on the same
12045/// trajectory the [`KUBE_KEY_RULES`] (a205eb3) /
12046/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12047/// [`CILIUM_API_VERSION`] (279d611) lifts established on the sibling
12048/// canonical-K8s-CR-rule-list-axis / canonical-Cilium-CRD-`kind` /
12049/// canonical-Cilium-CRD-`apiVersion` surfaces — extends the discipline
12050/// from the outer `(apiVersion, kind, spec)` shell of the Cilium CNP
12051/// down through the load-bearing `spec.ingress[].toPorts[].rules`
12052/// dispatch axis onto the port-set container half of the
12053/// `(toPorts, rules)` L4/L7-dispatch container-key pair, completing
12054/// the per-CNP L4/L7-dispatch-axis lift pair the M3 Aplicacao mesh
12055/// renderer's eBPF data-plane contract rests on. The render-side
12056/// consumer now threads the same `&'static str` through its
12057/// `ingress_rule.insert(…)` call so a future Cilium-CRD rebrand
12058/// on the port-set-container axis (or an upstream Cilium project
12059/// rename to a per-CRD sibling name — unlikely but the same
12060/// coordination point the prior lifts anchor for) lands in one place;
12061/// every future renderer that reaches for the canonical
12062/// per-CNP port-set-container-axis (the future M4
12063/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
12064/// CiliumNetworkPolicy fan-out, a future
12065/// `CiliumClusterwideNetworkPolicy` renderer that emits cluster-scoped
12066/// baseline-allow rules with the same `spec.ingress[].toPorts[]`
12067/// shape, a future `CiliumClusterwideEnvoyConfig` renderer whose
12068/// per-edge Envoy configuration nests under the same port-set
12069/// container-key convention) inherits the same value by construction
12070/// with no opportunity for per-renderer drift.
12071///
12072/// Same "the typed constant lives in one place" discipline the
12073/// [`KUBE_KEY_RULES`] (a205eb3) /
12074/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12075/// [`CILIUM_API_VERSION`] (279d611) lifts apply on the peer
12076/// canonical-Cilium-CNP-dispatch-axis surface.
12077///
12078/// [cm]: ../../caixa_mesh/index.html
12079pub const CILIUM_KEY_TO_PORTS: &str = "toPorts";
12080
12081/// Canonical Cilium `CiliumNetworkPolicy` destination-identity selector-
12082/// axis key every `cilium_network_policies`-emitted CNP document mounts
12083/// its L3-target `LabelSelector` under (`spec.endpointSelector`). Pairs
12084/// with the sibling [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) — the Cilium CNP
12085/// schema pins the destination workload through the `endpointSelector`
12086/// axis and the admitted L4 port set through the `toPorts` axis, so
12087/// drift on the destination-identity axis is exactly as load-bearing as
12088/// drift on the port-set-container axis it accompanies (the Cilium-
12089/// operator-side CRD schema validator drops any `spec` block whose
12090/// destination-identity axis carries an unrecognized key — an
12091/// `"endpointselector"` / `"endpointSelectors"` / `"endpoints"` typo
12092/// silently emits a CNP whose L3-target selector the Cilium operator's
12093/// per-CNP identity-resolution pass no-ops entirely: the policy binds
12094/// against no destination pods and every intra-mesh `:contratos` flow
12095/// the CNP was authored to allow drops at the eBPF data plane's
12096/// default-deny gate with no field naming the destination-identity-
12097/// axis-drift root cause).
12098///
12099/// The single source of truth the rendered Aplicacao Cilium-side mesh
12100/// bundle's per-CNP destination-identity-axis-naming reaches for:
12101///
12102///   - the rendered `CiliumNetworkPolicy` document's
12103///     `spec.endpointSelector` axis (caixa-mesh/src/lib.rs:990 —
12104///     the `cilium_network_policies` per-`(:de, :para)` policy's
12105///     `policy_spec.insert("endpointSelector", …)` call).
12106///
12107/// The destination-identity axis names the same Cilium-operator-side
12108/// per-CNP L3-target selector as the sibling [`CILIUM_KEY_TO_PORTS`]
12109/// per-ingress-rule port-set-container axis and must move together on
12110/// any future Cilium CRD schema rebrand (an upstream `cilium.io/v3`
12111/// rename of the destination-identity axis from `endpointSelector` to
12112/// `endpoints` / `targetSelector` / `destinationSelector`, coordinated
12113/// with the Cilium project's periodic CRD schema-migration passes).
12114/// Until this lift landed the axis carried an inline `endpointSelector`
12115/// literal at the one production-code occurrence in
12116/// caixa-mesh/src/lib.rs:990 (the `cilium_network_policies`
12117/// `policy_spec.insert("endpointSelector", …)` call) plus a matching
12118/// set inside the in-file
12119/// `cilium_policy_endpoint_selector_targets_destination_program` /
12120/// `cnp_endpoint_selector_carries_program_only_single_axis_shape` test-
12121/// fixture navigations — three occurrences of the same load-bearing
12122/// Cilium-CRD-`endpointSelector`-axis-key convention, drift-prone by
12123/// construction. A drift on any one production or test-fixture site
12124/// to `"endpointselector"` / `"endpointSelectors"` / `"endpoints"` would
12125/// have surfaced as a Cilium-operator-side schema validator drop at
12126/// apply time (the affected `spec` block's destination-identity axis
12127/// the CRD schema validator recognizes as unknown), with every intra-
12128/// mesh `:contratos` flow the CNP was authored to allow dropping at the
12129/// eBPF data plane's default-deny gate with no field naming the
12130/// destination-identity-drift root cause. A drift on the test-fixture
12131/// side silently masks the emission-side pin (`.get("endpointSelector")`
12132/// returns `None` under both the drifted-key emitter and the drifted-key
12133/// probe — the downstream `.and_then(|s| s.get("matchLabels"))` chain
12134/// short-circuits vacuously because the outer selector-lookup is itself
12135/// `None`).
12136///
12137/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12138/// "every recurring shape becomes a generator before it becomes a
12139/// pattern; every pattern becomes a library before it becomes
12140/// duplicated code. The duplication budget is zero.") promotes the
12141/// constant to a typed substrate-side `&'static str` on the same
12142/// trajectory the [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12143/// [`KUBE_KEY_RULES`] (a205eb3) /
12144/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12145/// [`CILIUM_API_VERSION`] (279d611) lifts established on the sibling
12146/// canonical-Cilium-CNP-dispatch-axis / canonical-Cilium-CRD-`kind` /
12147/// canonical-Cilium-CRD-`apiVersion` surfaces — extends the discipline
12148/// from the outer `(apiVersion, kind, spec)` shell of the Cilium CNP
12149/// and the per-ingress-rule `toPorts.rules` L4/L7-dispatch axis onto
12150/// the destination-identity half of the `(endpointSelector, ingress)`
12151/// per-CNP-body key pair, completing the per-CNP L3/L4/L7-triad lift
12152/// set the M3 Aplicacao mesh renderer's eBPF data-plane contract rests
12153/// on. The render-side consumer now threads the same `&'static str`
12154/// through its `policy_spec.insert(…)` call so a future Cilium-CRD
12155/// rebrand on the destination-identity axis (or an upstream Cilium
12156/// project rename to a per-CRD sibling name — unlikely but the same
12157/// coordination point the prior lifts anchor for) lands in one place;
12158/// every future renderer that reaches for the canonical per-CNP
12159/// destination-identity-axis (the future M4
12160/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
12161/// `CiliumNetworkPolicy` fan-out, a future
12162/// `CiliumClusterwideNetworkPolicy` renderer that emits cluster-scoped
12163/// baseline-allow rules with the same `spec.endpointSelector` shape, a
12164/// future `CiliumLocalRedirectPolicy` renderer whose per-Servico local-
12165/// redirect selector nests under the same destination-identity axis
12166/// convention) inherits the same value by construction with no
12167/// opportunity for per-renderer drift.
12168///
12169/// Same "the typed constant lives in one place" discipline the
12170/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12171/// [`KUBE_KEY_RULES`] (a205eb3) /
12172/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12173/// [`CILIUM_API_VERSION`] (279d611) lifts apply on the peer
12174/// canonical-Cilium-CNP-body-axis surface.
12175///
12176/// [cm]: ../../caixa_mesh/index.html
12177pub const CILIUM_KEY_ENDPOINT_SELECTOR: &str = "endpointSelector";
12178
12179/// Canonical Cilium `CiliumNetworkPolicy` traffic-direction container-
12180/// axis key every `cilium_network_policies`-emitted CNP document mounts
12181/// its inbound-per-`(:de, :para)` ingress-rule list under (`spec.ingress[]`).
12182/// Pairs with the sibling [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) +
12183/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) — the per-CNP `spec` schema mounts
12184/// the destination workload identity under `endpointSelector`, the
12185/// permitted inbound-per-`(:de, :para)` ingress-rule list under
12186/// `ingress[]`, and each per-ingress-rule port-set under
12187/// `ingress[].toPorts[]`, so drift on the traffic-direction axis is
12188/// exactly as load-bearing as drift on the destination-identity /
12189/// port-set-container axes it accompanies (the Cilium-operator-side CRD
12190/// schema validator drops any `spec` block whose traffic-direction axis
12191/// carries an unrecognized key — an `"Ingress"` / `"ingressRules"` /
12192/// `"inbound"` typo silently emits a CNP whose ingress-rule list the
12193/// Cilium operator's per-CNP L4/L7-dispatch pass no-ops entirely: the
12194/// policy binds against the destination workload but admits no ingress
12195/// traffic, and every intra-mesh `:contratos` flow the CNP was authored
12196/// to allow drops at the eBPF data plane's default-deny gate with no
12197/// field naming the traffic-direction-axis-drift root cause).
12198///
12199/// The single source of truth the rendered Aplicacao Cilium-side mesh
12200/// bundle's per-CNP traffic-direction-axis-naming reaches for:
12201///
12202///   - the rendered `CiliumNetworkPolicy` document's `spec.ingress[]`
12203///     axis (caixa-mesh/src/lib.rs:1036 — the `cilium_network_policies`
12204///     per-`(:de, :para)` policy's `policy_spec.insert("ingress", …)`
12205///     call).
12206///
12207/// The traffic-direction axis names the same Cilium-operator-side per-
12208/// CNP inbound-traffic dispatch container as the sibling
12209/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] destination-identity axis and
12210/// [`CILIUM_KEY_TO_PORTS`] per-ingress-rule port-set container-axis and
12211/// must move together on any future Cilium CRD schema rebrand (an
12212/// upstream `cilium.io/v3` rename of the traffic-direction axis from
12213/// `ingress` to `inbound` / `ingressRules` / `incoming`, coordinated
12214/// with the Cilium project's periodic CRD schema-migration passes, or
12215/// the introduction of a sibling `egress` axis for outbound-traffic
12216/// dispatch under the same per-CNP-body schema). Until this lift landed
12217/// the axis carried an inline `ingress` literal at the one production-
12218/// code occurrence in caixa-mesh/src/lib.rs:1036 (the
12219/// `cilium_network_policies` `policy_spec.insert("ingress", …)` call)
12220/// plus a matching set inside the in-file
12221/// `cilium_http_contracts_emit_l7_rules` /
12222/// `cilium_policies_are_identity_based` /
12223/// `cnp_from_endpoints_carries_program_plus_aplicacao_labels_two_axis_shape`
12224/// / `cilium_multiple_edges_same_pair_fold_into_one_policy` /
12225/// `cilium_pubsub_contracts_skip_l7_rules` /
12226/// `render_multi_doc_contains_expected_kinds` /
12227/// `cnp_authentication_carries_mtls_overlay_at_ingress_rule_level` /
12228/// `cnp_l4_fallback_port_routes_through_lifted_default_servico_port`
12229/// test-fixture navigations — nine occurrences of the same load-bearing
12230/// Cilium-CRD-`ingress`-axis-key convention, drift-prone by
12231/// construction. A drift on any one production or test-fixture site
12232/// to `"Ingress"` / `"ingressRules"` / `"inbound"` would have surfaced
12233/// as a Cilium-operator-side schema validator drop at apply time (the
12234/// affected `spec` block's traffic-direction axis the CRD schema
12235/// validator recognizes as unknown), with every intra-mesh `:contratos`
12236/// flow the CNP was authored to allow dropping at the eBPF data plane's
12237/// default-deny gate with no field naming the traffic-direction-drift
12238/// root cause. A drift on the test-fixture side silently masks the
12239/// emission-side pin (`.get("ingress")` returns `None` under both the
12240/// drifted-key emitter and the drifted-key probe — the downstream
12241/// `.and_then(|i| i.as_sequence())` chain short-circuits vacuously
12242/// because the outer traffic-direction-lookup is itself `None`, and
12243/// every per-CNP downstream navigation — `fromEndpoints`, `toPorts`,
12244/// `authentication` — rides through the same short-circuited outer
12245/// axis-lookup with no field naming the drift root cause).
12246///
12247/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12248/// "every recurring shape becomes a generator before it becomes a
12249/// pattern; every pattern becomes a library before it becomes
12250/// duplicated code. The duplication budget is zero.") promotes the
12251/// constant to a typed substrate-side `&'static str` on the same
12252/// trajectory the [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12253/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12254/// [`KUBE_KEY_RULES`] (a205eb3) /
12255/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12256/// [`CILIUM_API_VERSION`] (279d611) lifts established on the sibling
12257/// canonical-Cilium-CNP-destination-identity /
12258/// canonical-Cilium-CNP-port-set-container /
12259/// canonical-K8s-CR-rule-list / canonical-Cilium-CRD-`kind` /
12260/// canonical-Cilium-CRD-`apiVersion` surfaces — completes the per-CNP
12261/// L3/L4/L7-triad lift set `(endpointSelector, ingress → toPorts →
12262/// rules)` the M3 Aplicacao mesh renderer's eBPF data-plane contract
12263/// rests on by lifting the traffic-direction axis that structurally
12264/// separates the destination-identity axis from the port-set-container
12265/// axis nested beneath it. The render-side consumer now threads the
12266/// same `&'static str` through its `policy_spec.insert(…)` call so a
12267/// future Cilium-CRD rebrand on the traffic-direction axis (or an
12268/// upstream Cilium project rename to a per-CRD sibling name — unlikely
12269/// on the CRD's stable `cilium.io/v2` slot, but the coordination point
12270/// the prior lifts anchor for) lands in one place; every future
12271/// renderer that reaches for the canonical per-CNP traffic-direction-
12272/// axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
12273/// materializer's per-Aplicacao `CiliumNetworkPolicy` fan-out, a future
12274/// `CiliumClusterwideNetworkPolicy` renderer that emits cluster-scoped
12275/// baseline-allow rules with the same `spec.ingress[]` shape, a future
12276/// `CiliumLocalRedirectPolicy` renderer whose per-Servico local-
12277/// redirect ingress-rule list nests under the same traffic-direction
12278/// axis convention) inherits the same value by construction with no
12279/// opportunity for per-renderer drift.
12280///
12281/// Same "the typed constant lives in one place" discipline the
12282/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12283/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12284/// [`KUBE_KEY_RULES`] (a205eb3) /
12285/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12286/// [`CILIUM_API_VERSION`] (279d611) lifts apply on the peer
12287/// canonical-Cilium-CNP-body-axis surface.
12288///
12289/// [cm]: ../../caixa_mesh/index.html
12290pub const CILIUM_KEY_INGRESS: &str = "ingress";
12291
12292/// Canonical Cilium `CiliumNetworkPolicy` per-ingress-rule identity-
12293/// source selector-list axis key every `cilium_network_policies`-emitted
12294/// CNP document mounts its permitted-source `LabelSelector` list under
12295/// (`spec.ingress[].fromEndpoints[]`). Pairs with the sibling
12296/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) — the Cilium CNP schema
12297/// pins the destination workload identity through the per-CNP-body
12298/// `endpointSelector` axis and the admitted source workload identities
12299/// through the per-ingress-rule `fromEndpoints[]` axis, so drift on the
12300/// identity-source axis is exactly as load-bearing as drift on the
12301/// destination-identity axis it accompanies (the Cilium-operator-side
12302/// CRD schema validator drops any per-ingress-rule block whose
12303/// identity-source axis carries an unrecognized key — a
12304/// `"fromendpoints"` / `"fromEndPoint"` / `"sourceEndpoints"` typo
12305/// silently emits a CNP whose per-`(:de, :para)` ingress-rule identity-
12306/// source list the Cilium operator's per-CNP identity-resolution pass
12307/// no-ops entirely: the ingress rule admits no source pods and every
12308/// intra-mesh `:contratos` flow the CNP was authored to allow drops at
12309/// the eBPF data plane's default-deny gate with no field naming the
12310/// identity-source-axis-drift root cause).
12311///
12312/// The single source of truth the rendered Aplicacao Cilium-side mesh
12313/// bundle's per-ingress-rule identity-source-axis-naming reaches for:
12314///
12315///   - the rendered `CiliumNetworkPolicy` document's per-ingress-rule
12316///     `fromEndpoints[]` axis (caixa-mesh/src/lib.rs:991 — the
12317///     `cilium_network_policies` per-`(:de, :para)` policy's
12318///     `ingress_rule.insert("fromEndpoints", …)` call).
12319///
12320/// The identity-source axis names the same Cilium-operator-side per-
12321/// ingress-rule source-workload selector list as the sibling
12322/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] destination-identity axis and must
12323/// move together on any future Cilium CRD schema rebrand (an upstream
12324/// `cilium.io/v3` rename of the identity-source axis from
12325/// `fromEndpoints` to `sourceEndpoints` / `fromWorkloads` /
12326/// `sourceSelectors`, coordinated with the Cilium project's periodic
12327/// CRD schema-migration passes). Until this lift landed the axis
12328/// carried an inline `fromEndpoints` literal at the one production-code
12329/// occurrence in caixa-mesh/src/lib.rs:991 (the `cilium_network_policies`
12330/// `ingress_rule.insert("fromEndpoints", …)` call) plus a matching set
12331/// inside the in-file
12332/// `cnp_from_endpoints_carries_program_plus_aplicacao_labels_two_axis_shape`
12333/// / `cilium_policies_are_identity_based`
12334/// / `cnp_authentication_carries_mtls_overlay_at_ingress_rule_level`
12335/// test-fixture navigations — five occurrences of the same load-bearing
12336/// Cilium-CRD-`fromEndpoints`-axis-key convention, drift-prone by
12337/// construction. A drift on any one production or test-fixture site
12338/// to `"fromendpoints"` / `"fromEndPoint"` / `"sourceEndpoints"` would
12339/// have surfaced as a Cilium-operator-side schema validator drop at
12340/// apply time (the affected per-ingress-rule block's identity-source
12341/// axis the CRD schema validator recognizes as unknown), with every
12342/// intra-mesh `:contratos` flow the CNP was authored to allow dropping
12343/// at the eBPF data plane's default-deny gate with no field naming the
12344/// identity-source-drift root cause. A drift on the test-fixture side
12345/// silently masks the emission-side pin
12346/// (`.get("fromEndpoints")` returns `None` under both the drifted-key
12347/// emitter and the drifted-key probe — the downstream `.and_then(|e|
12348/// e.as_sequence())` / `.and_then(|e| e.get(KUBE_KEY_MATCH_LABELS))`
12349/// chain short-circuits vacuously because the outer identity-source-
12350/// lookup is itself `None`).
12351///
12352/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12353/// "every recurring shape becomes a generator before it becomes a
12354/// pattern; every pattern becomes a library before it becomes
12355/// duplicated code. The duplication budget is zero.") promotes the
12356/// constant to a typed substrate-side `&'static str` on the same
12357/// trajectory the [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12358/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12359/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12360/// [`KUBE_KEY_RULES`] (a205eb3) /
12361/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12362/// [`CILIUM_API_VERSION`] (279d611) lifts established on the sibling
12363/// canonical-Cilium-CNP-destination-identity /
12364/// canonical-Cilium-CNP-traffic-direction-container /
12365/// canonical-Cilium-CNP-port-set-container /
12366/// canonical-K8s-CR-rule-list / canonical-Cilium-CRD-`kind` /
12367/// canonical-Cilium-CRD-`apiVersion` surfaces — completes the per-CNP
12368/// identity-pair lift set `(endpointSelector, fromEndpoints)` the M3
12369/// Aplicacao mesh renderer's eBPF data-plane contract rests on by
12370/// lifting the identity-source axis structurally paired with the
12371/// destination-identity axis under the Cilium-operator-side per-CNP
12372/// SPIFFE-identity-bound access-control contract. The render-side
12373/// consumer now threads the same `&'static str` through its
12374/// `ingress_rule.insert(…)` call so a future Cilium-CRD rebrand on the
12375/// identity-source axis (or an upstream Cilium project rename to a
12376/// per-CRD sibling name — unlikely on the CRD's stable `cilium.io/v2`
12377/// slot, but the coordination point the prior lifts anchor for) lands
12378/// in one place; every future renderer that reaches for the canonical
12379/// per-ingress-rule identity-source-axis (the future M4
12380/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
12381/// `CiliumNetworkPolicy` fan-out, a future
12382/// `CiliumClusterwideNetworkPolicy` renderer that emits cluster-scoped
12383/// baseline-allow rules with the same `spec.ingress[].fromEndpoints[]`
12384/// shape, a future `CiliumLocalRedirectPolicy` renderer whose per-
12385/// Servico local-redirect source-workload selector list nests under
12386/// the same identity-source axis convention) inherits the same value
12387/// by construction with no opportunity for per-renderer drift.
12388///
12389/// Same "the typed constant lives in one place" discipline the
12390/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12391/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12392/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12393/// [`KUBE_KEY_RULES`] (a205eb3) /
12394/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12395/// [`CILIUM_API_VERSION`] (279d611) lifts apply on the peer
12396/// canonical-Cilium-CNP-body-axis surface.
12397///
12398/// [cm]: ../../caixa_mesh/index.html
12399pub const CILIUM_KEY_FROM_ENDPOINTS: &str = "fromEndpoints";
12400
12401/// Canonical Cilium `CiliumNetworkPolicy` per-`toPorts[]`-entry L4
12402/// port-tuple-list-container axis key every `cilium_network_policies`-
12403/// emitted CNP document mounts its per-port-set `[{port, protocol}]` list
12404/// under (`spec.ingress[].toPorts[].ports[]`). Nests inside the sibling
12405/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) — the Cilium CNP schema pins the
12406/// per-ingress-rule port-set-container axis through the `toPorts[]` list
12407/// and the per-port-set L4 port-tuple list through the `ports[]` axis
12408/// beneath each entry, so drift on the L4 port-tuple-list-container axis
12409/// is exactly as load-bearing as drift on the port-set container axis it
12410/// nests inside (the Cilium-operator-side CRD schema validator drops any
12411/// per-`toPorts[]` entry whose port-tuple-list-container axis carries an
12412/// unrecognized key — a `"port"` / `"portList"` / `"L4Ports"` typo
12413/// silently emits a CNP whose per-`(:de, :para)` per-port-set L4
12414/// port-tuple list the Cilium operator's per-CNP L4-allow eBPF-program
12415/// generation pass no-ops entirely: the port-set admits no `(port,
12416/// protocol)` tuple and every intra-mesh `:contratos` flow the CNP was
12417/// authored to allow drops at the eBPF data plane's default-deny gate
12418/// with no field naming the L4-port-tuple-list-container-axis-drift root
12419/// cause).
12420///
12421/// The single source of truth the rendered Aplicacao Cilium-side mesh
12422/// bundle's per-`toPorts[]`-entry L4-port-tuple-list-container-axis-
12423/// naming reaches for:
12424///
12425///   - the rendered `CiliumNetworkPolicy` document's per-`toPorts[]`-
12426///     entry `ports[]` axis (caixa-mesh/src/lib.rs:1081 — the
12427///     `cilium_network_policies` per-`(:de, :para)` policy's
12428///     `to_port.insert("ports", …)` call).
12429///
12430/// The L4 port-tuple-list-container axis names the same Cilium-operator-
12431/// side per-port-set L4-allow eBPF-program-generation source-list as the
12432/// sibling [`CILIUM_KEY_TO_PORTS`] port-set container axis it nests
12433/// inside and must move together on any future Cilium CRD schema rebrand
12434/// (an upstream `cilium.io/v3` rename of the L4 port-tuple-list axis
12435/// from `ports` to `portList` / `l4Ports` / `tuples`, coordinated with
12436/// the Cilium project's periodic CRD schema-migration passes). Until this
12437/// lift landed the axis carried an inline `ports` literal at the one
12438/// production-code occurrence in caixa-mesh/src/lib.rs:1081 (the
12439/// `cilium_network_policies` `to_port.insert("ports", …)` call) plus a
12440/// matching set inside the in-file
12441/// `cilium_pubsub_contracts_skip_l7_rules`
12442/// / `cnp_l4_fallback_port_reflects_default_servico_port`
12443/// test-fixture navigations — three occurrences of the same load-bearing
12444/// Cilium-CRD-`ports`-axis-key convention, drift-prone by construction. A
12445/// drift on any one production or test-fixture site to `"port"` /
12446/// `"portList"` / `"L4Ports"` would have surfaced as a Cilium-operator-
12447/// side schema validator drop at apply time (the affected per-`toPorts[]`
12448/// entry's port-tuple-list-container axis the CRD schema validator
12449/// recognizes as unknown), with every intra-mesh `:contratos` flow the
12450/// CNP was authored to allow dropping at the eBPF data plane's default-
12451/// deny gate with no field naming the L4-port-tuple-list-container-drift
12452/// root cause. A drift on the test-fixture side silently masks the
12453/// emission-side pin (`.get("ports")` returns `None` under both the
12454/// drifted-key emitter and the drifted-key probe — the downstream
12455/// `.and_then(|p| p.as_sequence())` / `.and_then(|s| s.first())` /
12456/// `.and_then(|p| p.get("port"))` chain short-circuits vacuously because
12457/// the outer L4-port-tuple-list-container lookup is itself `None`).
12458///
12459/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12460/// "every recurring shape becomes a generator before it becomes a
12461/// pattern; every pattern becomes a library before it becomes
12462/// duplicated code. The duplication budget is zero.") promotes the
12463/// constant to a typed substrate-side `&'static str` on the same
12464/// trajectory the [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
12465/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12466/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12467/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12468/// [`KUBE_KEY_RULES`] (a205eb3) /
12469/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12470/// [`CILIUM_API_VERSION`] (279d611) lifts established on the sibling
12471/// canonical-Cilium-CNP-identity-source /
12472/// canonical-Cilium-CNP-destination-identity /
12473/// canonical-Cilium-CNP-traffic-direction-container /
12474/// canonical-Cilium-CNP-port-set-container /
12475/// canonical-K8s-CR-rule-list / canonical-Cilium-CRD-`kind` /
12476/// canonical-Cilium-CRD-`apiVersion` surfaces — nests the per-port-set
12477/// L4 port-tuple-list-container axis structurally beneath the sibling
12478/// [`CILIUM_KEY_TO_PORTS`] port-set-container axis, extending the per-CNP
12479/// L3/L4/L7-triad `(endpointSelector, ingress → toPorts → ports / rules)`
12480/// lift set with the L4-half's port-tuple-list-container axis the M3
12481/// Aplicacao mesh renderer's eBPF data-plane L4-allow contract rests on.
12482/// The render-side consumer now threads the same `&'static str` through
12483/// its `to_port.insert(…)` call so a future Cilium-CRD rebrand on the
12484/// L4 port-tuple-list-container axis (or an upstream Cilium project
12485/// rename to a per-CRD sibling name — unlikely on the CRD's stable
12486/// `cilium.io/v2` slot, but the coordination point the prior lifts
12487/// anchor for) lands in one place; every future renderer that reaches
12488/// for the canonical per-`toPorts[]`-entry L4-port-tuple-list-container
12489/// axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
12490/// materializer's per-Aplicacao `CiliumNetworkPolicy` fan-out, a future
12491/// `CiliumClusterwideNetworkPolicy` renderer that emits cluster-scoped
12492/// baseline-allow rules with the same
12493/// `spec.ingress[].toPorts[].ports[]` shape, a future
12494/// `CiliumLocalRedirectPolicy` renderer whose per-Servico local-redirect
12495/// L4 port-tuple list nests under the same L4-port-tuple-list-container
12496/// axis convention) inherits the same value by construction with no
12497/// opportunity for per-renderer drift.
12498///
12499/// Same "the typed constant lives in one place" discipline the
12500/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
12501/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12502/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12503/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12504/// [`KUBE_KEY_RULES`] (a205eb3) /
12505/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12506/// [`CILIUM_API_VERSION`] (279d611) lifts apply on the peer
12507/// canonical-Cilium-CNP-body-axis surface.
12508///
12509/// [cm]: ../../caixa_mesh/index.html
12510pub const CILIUM_KEY_PORTS: &str = "ports";
12511
12512/// Canonical Cilium `CiliumNetworkPolicy` per-ingress-rule mutual-auth
12513/// policy body-axis key every `cilium_network_policies`-emitted CNP
12514/// document mounts its per-rule mTLS enforcement block under
12515/// (`spec.ingress[].authentication`). Sibling to
12516/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) +
12517/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) at the per-ingress-rule body
12518/// level — the Cilium CNP schema places the per-rule mutual-auth mode
12519/// (`{mode: required | disabled}`) at the ingress-rule axis alongside
12520/// the identity-source (`fromEndpoints`) and port-set (`toPorts`)
12521/// axes, so drift on the authentication axis is exactly as
12522/// load-bearing as drift on the sibling per-ingress-rule-body axes it
12523/// pairs with (the Cilium-operator-side CRD schema validator drops
12524/// any per-`ingress[]` entry whose mutual-auth axis carries an
12525/// unrecognized key — a `"auth"` / `"mutualAuth"` / `"mtls"` typo
12526/// silently emits a CNP whose per-`(:de, :para)` per-rule mTLS block
12527/// the Cilium operator's per-CNP mutual-auth SPIFFE-handshake
12528/// pipeline no-ops entirely: the ingress rule falls back to the
12529/// cluster-default authentication mode (typically `"disabled"` — no
12530/// mutual-auth enforcement), and every intra-mesh `:contratos` flow
12531/// the CNP was authored to protect with per-edge mTLS silently
12532/// bypasses the SPIFFE-identity-bound mutual-auth handshake with no
12533/// field naming the mutual-auth-axis-drift root cause).
12534///
12535/// The single source of truth the rendered Aplicacao Cilium-side
12536/// mesh bundle's per-ingress-rule mutual-auth-axis naming reaches for:
12537///
12538///   - the rendered `CiliumNetworkPolicy` document's per-`ingress[]`
12539///     entry `authentication` axis (caixa-mesh/src/lib.rs — the
12540///     `cilium_network_policies` per-`(:de, :para)` policy's
12541///     `ingress_rule.insert("authentication", …)` call in the
12542///     `:politicas :mtls-required` overlay emit gate).
12543///
12544/// The mutual-auth axis names the same Cilium-operator-side per-rule
12545/// SPIFFE-identity-handshake enforcement policy as the sibling per-
12546/// ingress-rule identity-source (`fromEndpoints`) and port-set
12547/// (`toPorts`) axes it pairs with, and must move together on any
12548/// future Cilium CRD schema rebrand (an upstream `cilium.io/v3`
12549/// rename of the mutual-auth axis from `authentication` to
12550/// `mutualAuth` / `mtls` / `authPolicy`, coordinated with the Cilium
12551/// project's periodic CRD schema-migration passes). Until this lift
12552/// landed the axis carried an inline `authentication` literal at the
12553/// one production-code emitter site (the `cilium_network_policies`
12554/// per-rule `ingress_rule.insert("authentication", …)` call in the
12555/// `:mtls-required` overlay emit gate) plus a matching set inside
12556/// the in-file `cnp_authentication_renders_every_policy_independently`
12557/// / `cnp_authentication_position_is_rule_level_not_nested` /
12558/// `cnp_authentication_pubsub_contracts_carry_overlay_too` /
12559/// `cnp_authentication_mode_is_a_yaml_string_scalar` /
12560/// `cnp_omits_authentication_when_mtls_required_unset` /
12561/// `cnp_explicit_mtls_required_false_emits_disabled_mode` /
12562/// `cnp_authentication_overlay_when_mtls_required_set` (name approximate)
12563/// test-fixture navigations — ten occurrences of the same
12564/// load-bearing Cilium-CRD-mutual-auth-axis-key convention, drift-
12565/// prone by construction. A drift on any one production or test-
12566/// fixture site to `"auth"` / `"mutualAuth"` / `"mtls"` would surface
12567/// as a Cilium-operator-side schema-validator drop at apply time
12568/// (the affected per-`ingress[]` entry's mutual-auth-axis key the
12569/// CRD schema validator recognizes as unknown), with every intra-
12570/// mesh `:contratos` flow the CNP was authored to protect with per-
12571/// edge SPIFFE-identity-bound mutual-auth silently bypassing the
12572/// mTLS handshake at the Cilium data-plane's default-authentication
12573/// mode with no field naming the mutual-auth-axis-drift root cause.
12574/// A drift on the test-fixture side silently masks the emission-
12575/// side pin (`.get("authentication")` returns `None` under both the
12576/// drifted-key emitter and the drifted-key probe — every downstream
12577/// `.and_then(|a| a.get("mode"))` chain short-circuits vacuously
12578/// because the outer mutual-auth-body-lookup is itself `None`).
12579///
12580/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12581/// "every recurring shape becomes a generator before it becomes a
12582/// pattern; every pattern becomes a library before it becomes
12583/// duplicated code. The duplication budget is zero.") promotes the
12584/// constant to a typed substrate-side `&'static str` on the same
12585/// trajectory the [`CILIUM_KEY_PORTS`] (1087693) /
12586/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
12587/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12588/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12589/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12590/// [`KUBE_KEY_RULES`] (a205eb3) /
12591/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12592/// [`CILIUM_API_VERSION`] (279d611) lifts established on the
12593/// sibling canonical-Cilium-CNP-body-axis surfaces — nests the
12594/// per-ingress-rule mutual-auth axis structurally beside the sibling
12595/// [`CILIUM_KEY_FROM_ENDPOINTS`] identity-source and
12596/// [`CILIUM_KEY_TO_PORTS`] port-set-container axes at the per-rule
12597/// body triple `(fromEndpoints, toPorts, authentication)` the M3
12598/// Aplicacao mesh renderer's SPIFFE-identity-bound per-edge mTLS
12599/// contract rests on.
12600///
12601/// [cm]: ../../caixa_mesh/index.html
12602pub const CILIUM_KEY_AUTHENTICATION: &str = "authentication";
12603
12604/// Canonical Cilium `CiliumNetworkPolicy` per-`ingress[].authentication`
12605/// block mTLS-mode-discriminator leaf-scalar-axis key every
12606/// `cilium_network_policies`-emitted CNP document mounts its per-rule
12607/// mutual-auth mode leaf under (`spec.ingress[].authentication.mode`).
12608/// Nests exactly one level beneath the sibling
12609/// [`CILIUM_KEY_AUTHENTICATION`] (db31108) per-ingress-rule mutual-auth
12610/// body-axis it sits inside: the Cilium CNP schema places the mTLS
12611/// enforcement mode discriminator (`"required"` / `"disabled"`) as the
12612/// single leaf-scalar axis of the per-rule authentication block, so
12613/// drift on the mode-discriminator leaf axis is exactly as load-bearing
12614/// as drift on the sibling per-ingress-rule mutual-auth body-axis key
12615/// (`authentication`) it nests inside (the Cilium-operator-side CNP
12616/// schema validator drops any per-`ingress[]` entry whose per-rule
12617/// mutual-auth block carries an unrecognized leaf axis — a `"policy"` /
12618/// `"authMode"` / `"handshakeMode"` typo at either the emit-side single-
12619/// field-overlay call site or a downstream renderer's per-rule authn
12620/// leaf upsert silently emits a per-`ingress[]` mutual-auth block whose
12621/// mode-discriminator leaf the Cilium CRD schema validator rejects as
12622/// unknown; the ingress rule falls back to the cluster-default
12623/// authentication mode (typically `"disabled"` — no mutual-auth
12624/// enforcement) silently bypassing the SPIFFE-identity-bound mTLS
12625/// handshake every intra-mesh `:contratos` flow the CNP was authored to
12626/// protect with per-edge mTLS, and the emit-side/probe-side split
12627/// silently masks the per-rule mutual-auth pin (`.get("mode")` returns
12628/// `None` under both the drifted-key emitter and the drifted-key probe
12629/// — every downstream `.and_then(|v| v.as_str())` chain short-circuits
12630/// vacuously because the outer mode-leaf-lookup is itself `None`).
12631///
12632/// The single source of truth the rendered Aplicacao Cilium-side mesh
12633/// bundle's per-ingress-rule mutual-auth-mode-leaf-axis naming reaches
12634/// for:
12635///
12636///   - the rendered `CiliumNetworkPolicy` document's per-`ingress[]`
12637///     entry `authentication.mode` leaf axis (caixa-mesh/src/lib.rs —
12638///     the `cilium_network_policies` per-`(:de, :para)` policy's
12639///     `single_field_overlay(spec.politicas.mtls_required, "mode", …)`
12640///     call site in the `:politicas :mtls-required` overlay emit gate,
12641///     the exact field the `single_field_overlay` helper writes the
12642///     single leaf under when the tristate `:mtls-required` slot is
12643///     set).
12644///
12645/// The mode-discriminator leaf-axis names the same Cilium-operator-side
12646/// per-rule SPIFFE-identity-handshake enforcement policy as the sibling
12647/// per-ingress-rule mutual-auth-body-axis key (`authentication`) it nests
12648/// inside, and must move together on any future Cilium CRD schema
12649/// rebrand (an upstream `cilium.io/v3` rename of the mutual-auth mode-
12650/// discriminator leaf from `mode` to `policy` / `authMode` /
12651/// `handshakeMode`, coordinated with the Cilium project's periodic CRD
12652/// schema-migration passes). Until this lift landed the axis carried an
12653/// inline `mode` literal at the one production-code emitter site (the
12654/// `cilium_network_policies` per-rule `single_field_overlay(...,
12655/// "mode", ...)` call in the `:mtls-required` overlay emit gate) plus a
12656/// matching set inside the in-file `cnp_carries_politicas_mtls_required_
12657/// on_every_rule` / `cnp_explicit_mtls_required_false_emits_disabled_
12658/// mode` / `cnp_authentication_renders_every_policy_independently` /
12659/// `cnp_authentication_pubsub_contracts_carry_overlay_too` /
12660/// `cnp_authentication_mode_is_a_yaml_string_scalar` test-fixture
12661/// navigations — six occurrences of the same load-bearing Cilium-CRD-
12662/// mutual-auth-mode-discriminator-leaf-axis-key convention, drift-prone
12663/// by construction. A drift on any one production or test-fixture site
12664/// to `"policy"` / `"authMode"` / `"handshakeMode"` would surface as a
12665/// Cilium-operator-side schema-validator drop at apply time (the
12666/// affected per-`ingress[]` entry's per-rule mutual-auth-mode-
12667/// discriminator-leaf-axis key the CRD schema validator recognizes as
12668/// unknown), with every intra-mesh `:contratos` flow the CNP was
12669/// authored to protect with per-edge SPIFFE-identity-bound mutual-auth
12670/// silently bypassing the mTLS handshake at the Cilium data-plane's
12671/// default-authentication mode with no field naming the mutual-auth-
12672/// mode-discriminator-leaf-axis-drift root cause.
12673///
12674/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12675/// "every recurring shape becomes a generator before it becomes a
12676/// pattern; every pattern becomes a library before it becomes
12677/// duplicated code. The duplication budget is zero.") promotes the
12678/// constant to a typed substrate-side `&'static str` on the same
12679/// trajectory the [`CILIUM_KEY_AUTHENTICATION`] (db31108) /
12680/// [`CILIUM_KEY_PORTS`] (1087693) /
12681/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
12682/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12683/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12684/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12685/// [`KUBE_KEY_RULES`] (a205eb3) /
12686/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12687/// [`CILIUM_API_VERSION`] (279d611) lifts established on the
12688/// sibling canonical-Cilium-CNP-body-axis surfaces — descends the
12689/// per-ingress-rule mutual-auth mode-discriminator leaf axis one level
12690/// beneath the parent [`CILIUM_KEY_AUTHENTICATION`] body-axis key it
12691/// pairs with, completing the per-rule mutual-auth
12692/// `(authentication → mode)` body/leaf axis pair the M3 Aplicacao mesh
12693/// renderer's SPIFFE-identity-bound per-edge mTLS enforcement contract
12694/// rests on.
12695///
12696/// [cm]: ../../caixa_mesh/index.html
12697pub const CILIUM_KEY_MODE: &str = "mode";
12698
12699/// Canonical Cilium `CiliumNetworkPolicy` per-`ingress[].toPorts[].rules`
12700/// L7-HTTP-rule-list-discriminator container-axis key every
12701/// `cilium_network_policies`-emitted CNP document mounts its per-`toPorts[]`
12702/// entry L7 HTTP-rule list under (`spec.ingress[].toPorts[].rules.http`).
12703/// Nests exactly one level beneath the sibling [`KUBE_KEY_RULES`] (a205eb3)
12704/// per-`toPorts[]` rule-list-container axis it sits inside: the Cilium CNP
12705/// schema places the L7-protocol-selection discriminator (`http` / future
12706/// `kafka` / future `dns`) as the single per-protocol keyed axis of the
12707/// per-`toPorts[]` rules block, so drift on the L7-HTTP-rule-list-
12708/// discriminator axis is exactly as load-bearing as drift on the sibling
12709/// [`KUBE_KEY_RULES`] per-`toPorts[]` rule-list-container axis-key it nests
12710/// inside (the Cilium-operator-side CNP schema validator drops any per-
12711/// `toPorts[]` entry whose per-protocol L7-rule-list-discriminator key it
12712/// recognizes as unknown — a `"HTTP"` / `"Http"` / `"http/1.1"` /
12713/// `"httpRules"` typo at either the emit-side `rules.insert(…)` call site
12714/// or a downstream renderer's per-`toPorts[]` L7-rule-list upsert silently
12715/// emits a per-`toPorts[]` entry whose L7-HTTP-rule-list-discriminator key
12716/// the Cilium CRD schema validator rejects as unknown; the per-`toPorts[]`
12717/// entry falls back to L4-only enforcement — no L7 URL-path predicate is
12718/// applied — silently admitting every HTTP-method / URL-path combination
12719/// the ingress rule was authored to filter to the exact path prefix set
12720/// the typed `:contratos` graph names at the L7 introspection axis, and
12721/// the emit-side/probe-side split silently masks the per-`toPorts[]` L7-
12722/// rule-list pin (`.get("http")` returns `None` under both the drifted-
12723/// key emitter and the drifted-key probe — every downstream
12724/// `.and_then(|h| h.as_sequence())` chain short-circuits vacuously because
12725/// the outer L7-HTTP-rule-list-lookup is itself `None`).
12726///
12727/// The single source of truth the rendered Aplicacao Cilium-CNP-side
12728/// intra-mesh L7-tuple-gating bundle's per-`toPorts[]` L7-HTTP-rule-list-
12729/// discriminator-axis naming reaches for:
12730///
12731///   - the rendered `CiliumNetworkPolicy` document's per-`toPorts[]` entry
12732///     `rules.http` L7-HTTP-rule-list-discriminator axis (caixa-mesh/src/lib.rs —
12733///     the `cilium_network_policies` per-`(:de, :para)` policy's
12734///     `rules.insert("http", …)` call in the `WitTarget::Http` L7-
12735///     introspection emit branch, the exact per-protocol keyed axis of
12736///     the per-`toPorts[]` rules block the L7 URL-path predicate lands
12737///     under).
12738///
12739/// The L7-HTTP-rule-list-discriminator axis names the same Cilium-operator-
12740/// side per-`toPorts[]` L7 URL-path predicate selection as the sibling
12741/// [`KUBE_KEY_RULES`] per-`toPorts[]` rule-list-container axis-key it nests
12742/// inside, and must move together on any future Cilium CRD schema rebrand
12743/// (an upstream `cilium.io/v3` rename of the L7-HTTP-rule-list-
12744/// discriminator from `http` to `httpRules` / `l7Http` / `httpMatch`,
12745/// coordinated with the Cilium project's periodic CRD schema-migration
12746/// passes). Until this lift landed the axis carried an inline `http`
12747/// literal at the one production-code emitter site (the
12748/// `cilium_network_policies` per-`(:de, :para)` `rules.insert("http", …)`
12749/// call in the `WitTarget::Http` L7 introspection emit branch) plus a
12750/// matching set inside the in-file `cilium_l7_rules_fan_in_captures_every_
12751/// http_edge` / `cilium_http_contracts_carry_l7_path` test-fixture
12752/// navigations — three occurrences of the same load-bearing Cilium-CRD-
12753/// L7-HTTP-rule-list-discriminator convention, drift-prone by
12754/// construction. A drift on any one production or test-fixture site to
12755/// `"HTTP"` / `"Http"` / `"httpRules"` would surface as a Cilium-operator-
12756/// side schema-validator drop at apply time (the affected per-
12757/// `toPorts[]` entry's L7-rule-list-discriminator key the CRD schema
12758/// validator recognizes as unknown), with every intra-mesh HTTP-shaped
12759/// `:contratos` flow the CNP was authored to filter to a URL-path prefix
12760/// silently bypassing the L7 path predicate at the Cilium data-plane's
12761/// L4-only fallback dispatch with no field naming the L7-HTTP-rule-list-
12762/// discriminator-drift root cause.
12763///
12764/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12765/// "every recurring shape becomes a generator before it becomes a
12766/// pattern; every pattern becomes a library before it becomes
12767/// duplicated code. The duplication budget is zero.") promotes the
12768/// constant to a typed substrate-side `&'static str` on the same
12769/// trajectory the [`CILIUM_KEY_MODE`] (4289dfb) /
12770/// [`CILIUM_KEY_AUTHENTICATION`] (db31108) /
12771/// [`CILIUM_KEY_PORTS`] (1087693) /
12772/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
12773/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12774/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12775/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12776/// [`KUBE_KEY_RULES`] (a205eb3) /
12777/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12778/// [`CILIUM_API_VERSION`] (279d611) lifts established on the
12779/// sibling canonical-Cilium-CNP-body-axis surfaces — descends the per-
12780/// `toPorts[]` L7-HTTP-rule-list-discriminator axis one level beneath the
12781/// parent [`KUBE_KEY_RULES`] per-`toPorts[]` rule-list-container axis-key
12782/// it nests inside, completing the per-`toPorts[]` L7-introspection
12783/// `(rules → http)` container/protocol-discriminator axis pair the M3
12784/// Aplicacao mesh renderer's HTTP-shaped-`:contratos` URL-path-prefix-
12785/// filtering L7-enforcement contract rests on.
12786///
12787/// [cm]: ../../caixa_mesh/index.html
12788pub const CILIUM_KEY_HTTP: &str = "http";
12789
12790/// Canonical Cilium `CiliumNetworkPolicy` per-`ingress[].toPorts[].rules.http[]`
12791/// per-HTTP-rule URL-path-predicate leaf-scalar-axis key every
12792/// `cilium_network_policies`-emitted CNP document mounts its per-HTTP-rule
12793/// URL-path-prefix predicate scalar under
12794/// (`spec.ingress[].toPorts[].rules.http[].path`). Nests exactly one level
12795/// beneath the sibling [`CILIUM_KEY_HTTP`] (ccd81e8) per-`toPorts[]`
12796/// L7-HTTP-rule-list-discriminator container-axis it sits inside: the Cilium
12797/// CNP schema places the per-HTTP-rule URL-path predicate scalar (the exact
12798/// URL-path regex the Cilium L7 dispatch pass matches the observed HTTP
12799/// request line's path segment against) as the single load-bearing leaf-
12800/// scalar axis of the per-`rules.http[]` entry — so drift on the per-HTTP-
12801/// rule URL-path-predicate leaf axis is exactly as load-bearing as drift on
12802/// the sibling [`CILIUM_KEY_HTTP`] per-`toPorts[]` L7-HTTP-rule-list-
12803/// discriminator container-axis key it nests inside (the Cilium-operator-
12804/// side CNP schema validator drops any per-`rules.http[]` entry whose per-
12805/// HTTP-rule URL-path-predicate leaf key it recognizes as unknown — a
12806/// `"Path"` / `"pathPrefix"` / `"regex"` / `"urlPath"` / `"pathMatch"` typo
12807/// at either the emit-side `http_rule.insert(…)` call site or a downstream
12808/// renderer's per-`rules.http[]` URL-path leaf upsert silently emits a per-
12809/// `rules.http[]` entry whose URL-path-predicate leaf-axis key the Cilium
12810/// CRD schema validator rejects as unknown; the per-`rules.http[]` entry
12811/// falls back to a match-any-URL-path predicate — the per-`toPorts[]` L7
12812/// rule admits every URL path on the destination port silently, bypassing
12813/// the URL-path-prefix predicate the typed `:contratos` HTTP-shaped edge's
12814/// `:endpoint` slot names at the L7 introspection axis, and the emit-
12815/// side/probe-side split silently masks the per-`rules.http[]` URL-path
12816/// pin (`.get("path")` returns `None` under both the drifted-key emitter
12817/// and the drifted-key probe — every downstream `.and_then(|v| v.as_str())`
12818/// chain short-circuits vacuously because the outer per-HTTP-rule URL-
12819/// path-lookup is itself `None`).
12820///
12821/// The single source of truth the rendered Aplicacao Cilium-CNP-side
12822/// intra-mesh per-`toPorts[]` L7-URL-path-predicate-gating bundle's per-
12823/// `rules.http[]` URL-path-predicate-leaf-axis naming reaches for:
12824///
12825///   - the rendered `CiliumNetworkPolicy` document's per-`toPorts[]`
12826///     `rules.http[]` entry's `path` URL-path-predicate leaf axis
12827///     (caixa-mesh/src/lib.rs — the `cilium_network_policies` per-`(:de,
12828///     :para)` policy's `http_rule.insert("path", …)` call in the
12829///     `WitTarget::Http` L7 introspection emit branch, the exact per-
12830///     `rules.http[]` leaf axis the per-HTTP-rule URL-path predicate scalar
12831///     lands under, seeded from the typed HTTP-shaped `:contratos` edge's
12832///     `:endpoint` slot).
12833///
12834/// The per-HTTP-rule URL-path-predicate-leaf-axis names the same Cilium-
12835/// operator-side per-`rules.http[]` URL-path predicate selection as the
12836/// sibling [`CILIUM_KEY_HTTP`] per-`toPorts[]` L7-HTTP-rule-list-
12837/// discriminator container-axis key it nests inside, and must move together
12838/// on any future Cilium CRD schema rebrand (an upstream `cilium.io/v3`
12839/// rename of the per-HTTP-rule URL-path-predicate leaf from `path` to
12840/// `urlPath` / `pathPrefix` / `pathMatch`, coordinated with the Cilium
12841/// project's periodic CRD schema-migration passes). Until this lift landed
12842/// the axis carried an inline `path` literal at the one production-code
12843/// emitter site (the `cilium_network_policies` per-`(:de, :para)`
12844/// `http_rule.insert("path", …)` call in the `WitTarget::Http` L7
12845/// introspection emit branch) plus a matching set inside the in-file
12846/// `cilium_http_contracts_emit_l7_rules` test-fixture per-HTTP-rule URL-
12847/// path-predicate presence-and-value pin — two occurrences of the same
12848/// load-bearing Cilium-CRD per-HTTP-rule URL-path-predicate-leaf-axis
12849/// convention, drift-prone by construction. A drift on any one production
12850/// or test-fixture site to `"Path"` / `"pathPrefix"` / `"regex"` /
12851/// `"urlPath"` / `"pathMatch"` would surface as a Cilium-operator-side
12852/// schema-validator drop at apply time (the affected per-`rules.http[]`
12853/// entry's URL-path-predicate leaf-axis key the CRD schema validator
12854/// recognizes as unknown), with every intra-mesh HTTP-shaped `:contratos`
12855/// flow the CNP was authored to filter to a URL-path prefix silently
12856/// bypassing the L7 URL-path predicate at the Cilium data-plane's match-
12857/// any-URL-path fallback with no field naming the URL-path-predicate-
12858/// leaf-axis-drift root cause.
12859///
12860/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12861/// "every recurring shape becomes a generator before it becomes a
12862/// pattern; every pattern becomes a library before it becomes
12863/// duplicated code. The duplication budget is zero.") promotes the
12864/// constant to a typed substrate-side `&'static str` on the same
12865/// trajectory the [`CILIUM_KEY_HTTP`] (ccd81e8) /
12866/// [`CILIUM_KEY_MODE`] (4289dfb) /
12867/// [`CILIUM_KEY_AUTHENTICATION`] (db31108) /
12868/// [`CILIUM_KEY_PORTS`] (1087693) /
12869/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
12870/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
12871/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
12872/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
12873/// [`KUBE_KEY_RULES`] (a205eb3) /
12874/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12875/// [`CILIUM_API_VERSION`] (279d611) lifts established on the
12876/// sibling canonical-Cilium-CNP-body-axis surfaces — descends the per-
12877/// `toPorts[]` L7-introspection `(rules → http → path)` container /
12878/// protocol-discriminator / URL-path-predicate axis chain one leaf level
12879/// beneath the parent [`CILIUM_KEY_HTTP`] per-`toPorts[]` L7-HTTP-rule-
12880/// list-discriminator axis-key it nests inside, completing the per-
12881/// `toPorts[]` L7-introspection `(rules → http → path)` container /
12882/// protocol-discriminator / URL-path-predicate axis triple the M3
12883/// Aplicacao mesh renderer's HTTP-shaped-`:contratos` URL-path-prefix-
12884/// filtering L7-enforcement contract rests on.
12885///
12886/// Distinct from the sibling K8s-Gateway-API-side
12887/// [`GATEWAY_API_KEY_PATH`] (9f45aa4) per-`HTTPRouteMatch` path-matcher
12888/// container-axis key: both keys spell the same underlying `"path"`
12889/// string but name distinct schema axes on distinct CRD groups — the
12890/// Cilium-side axis is a per-HTTP-rule URL-path predicate leaf scalar
12891/// on the Cilium `cilium.io/v2` `CiliumNetworkPolicy` CRD's per-
12892/// `toPorts[].rules.http[]` entry, the Gateway-API-side axis is a per-
12893/// `HTTPRouteMatch` path-matcher two-leaf container (`{type, value}`)
12894/// on the K8s Gateway API v1 `HTTPRoute` CRD's `spec.rules[].matches[]`
12895/// entry. Keeping them as sibling `pub const` declarations (rather than
12896/// coalescing onto a single shared constant that happens to carry the
12897/// same string) mirrors the deliberate axis-independence discipline the
12898/// [`CILIUM_KIND_NETWORK_POLICY`] / [`GATEWAY_API_KIND_GATEWAY`] /
12899/// [`GATEWAY_API_KIND_HTTP_ROUTE`] kind-discriminator lifts already
12900/// codified on the sibling per-CRD-kind axes, so a future Cilium-side
12901/// per-HTTP-rule URL-path-predicate rebrand (Cilium `cilium.io/v3` renames
12902/// `path` → `urlPath`) can land independently of the Gateway-API-side
12903/// per-`HTTPRouteMatch` path-matcher container-axis rebrand without any
12904/// cross-CRD coordination footgun where a shared constant would force a
12905/// coupled edit against schema evolutions the two CRD projects run on
12906/// independent cadences. Note: Rust's `&'static str` interner coalesces
12907/// identical byte-sequences onto one storage allocation at codegen time,
12908/// so at runtime a `.as_ptr()` comparison between the two constants can't
12909/// distinguish "sibling `pub const` declarations carrying identical
12910/// bytes" from "coalesced canonical declaration" — the axis-independence
12911/// discipline lives at the rustc symbol-name axis (the two `pub const
12912/// CILIUM_KEY_PATH` / `pub const GATEWAY_API_KEY_PATH` symbols a future
12913/// rebrand of one leaves the other structurally untouched under) rather
12914/// than the runtime-address axis, and the per-axis re-export identity
12915/// pins in the consuming renderer crates (each pinning the local re-
12916/// export against its own canonical declaration on its own axis) remain
12917/// the load-bearing "no sibling local `pub const` drift" gate for the
12918/// pair.
12919///
12920/// [cm]: ../../caixa_mesh/index.html
12921pub const CILIUM_KEY_PATH: &str = "path";
12922
12923/// Canonical K8s Gateway API CRD `kind` discriminator the rendered
12924/// `Gateway` document declares at its top-level [`KUBE_KEY_KIND`] axis.
12925/// Pairs with the sibling [`GATEWAY_API_API_VERSION`] (3c6cfc3) — the
12926/// K8s apiserver-side CRD resolution contract is the
12927/// `(apiVersion, kind)` tuple keyed against the registered
12928/// `CustomResourceDefinition`, so drift on the kind axis is exactly as
12929/// load-bearing as drift on the apiVersion axis it accompanies (the
12930/// apiserver's `RESTMapper` consults both together; a
12931/// `("gateway.networking.k8s.io/v1", "Gatway")` typo at the production-
12932/// code call site lands outside the registered Gateway-API-conformant
12933/// `Gateway` CRD's `RESTKind` lookup, surfacing apply-side as a
12934/// non-self-locating "no kind 'Gatway' is registered for version
12935/// 'gateway.networking.k8s.io/v1'" error far from the source caixa.lisp
12936/// / the renderer's [`kube_resource_skeleton`] call site).
12937///
12938/// The single source of truth the rendered Aplicacao Gateway-API-side
12939/// ingress bundle's `Gateway`-naming axis reaches for:
12940///
12941///   - the rendered `Gateway` document's top-level [`KUBE_KEY_KIND`]
12942///     axis (caixa-mesh/src/lib.rs:578 — the `gateway_routes` per-
12943///     Aplicacao `Gateway` [`kube_resource_skeleton`] kind argument).
12944///
12945/// The kind axis names the same Gateway-API-conformant CRD discriminator
12946/// as the sibling [`GATEWAY_API_API_VERSION`] apiVersion axis and must
12947/// move together on any future Gateway-API rebrand. Until this lift
12948/// landed the axis carried an inline `Gateway` literal at the one
12949/// production-code occurrence in caixa-mesh/src/lib.rs:578 (the
12950/// `gateway_routes` `Gateway` [`kube_resource_skeleton`] kind argument)
12951/// plus a matching set inside the in-file
12952/// `gateway_carries_canonical_kube_skeleton_without_labels` /
12953/// `render_all_includes_every_artifact_kind` test fixtures plus the
12954/// `find()` predicate of every per-Gateway-kind test that picks the
12955/// `Gateway` document out of the rendered Aplicacao mesh bundle — five
12956/// occurrences of the same load-bearing Gateway-API-CRD-`kind`-
12957/// discriminator convention, drift-prone by construction. A drift on
12958/// the top-level `Gateway` `kind` axis would have surfaced as a
12959/// non-self-locating "no kind 'Gatway' is registered for version
12960/// 'gateway.networking.k8s.io/v1'" error far from the source caixa.lisp
12961/// at apply parse time, with the rendered per-Aplicacao Gateway never
12962/// landing in the apiserver-side CRD registration and every external
12963/// `:entrada` flow dropping at the gateway-class-controller's reconcile
12964/// loop with no field naming the kind-discriminator-drift root cause.
12965///
12966/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
12967/// "every recurring shape becomes a generator before it becomes a
12968/// pattern; every pattern becomes a library before it becomes
12969/// duplicated code. The duplication budget is zero.") promotes the
12970/// constant to a typed substrate-side `&'static str` on the same
12971/// trajectory the [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12972/// [`FLUX_KIND_KUSTOMIZATION`] (4114773) /
12973/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
12974/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
12975/// [`GATEWAY_API_API_VERSION`] (3c6cfc3) lifts established on the
12976/// sibling cluster-side-CRD-`kind`-discriminator + canonical-CRD-
12977/// group/version axes — extends the discipline from the apiVersion
12978/// half of the `(apiVersion, kind)` CRD-lookup tuple onto the kind
12979/// half on the same Gateway-API-CRD-axis, beginning the per-Gateway-
12980/// API-CRD kind+apiVersion lift pair the M3 Aplicacao mesh renderer's
12981/// external `:entrada` ingress contract rests on. The render-side
12982/// consumer now threads the same `&'static str` through its
12983/// [`kube_resource_skeleton`] call so a future Gateway-API rebrand
12984/// lands in one place; every future renderer that reaches for the
12985/// canonical Gateway-API `Gateway` kind (the future M4
12986/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
12987/// Gateway fan-out, a future per-cluster `GatewayClass` renderer the
12988/// operator emits for per-cluster gateway-class scoping, a future
12989/// per-edge `TCPRoute` / `TLSRoute` / `GRPCRoute` renderer for non-HTTP
12990/// `:entrada` edges that pair against this same `Gateway` parent)
12991/// inherits the same value by construction with no opportunity for
12992/// per-renderer drift.
12993///
12994/// Same "the typed constant lives in one place" discipline the
12995/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
12996/// [`FLUX_KIND_KUSTOMIZATION`] (4114773) /
12997/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
12998/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
12999/// [`GATEWAY_API_API_VERSION`] (3c6cfc3) /
13000/// [`CILIUM_API_VERSION`] (279d611) lifts apply on the peer
13001/// canonical-cluster-side-CRD-discriminator surface.
13002///
13003/// [cm]: ../../caixa_mesh/index.html
13004pub const GATEWAY_API_KIND_GATEWAY: &str = "Gateway";
13005
13006/// Canonical K8s Gateway API CRD `kind` discriminator the rendered
13007/// `HTTPRoute` document declares at its top-level [`KUBE_KEY_KIND`] axis.
13008/// Pairs with the sibling [`GATEWAY_API_API_VERSION`] (3c6cfc3) and the
13009/// peer [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) — the K8s apiserver-side
13010/// CRD resolution contract is the `(apiVersion, kind)` tuple keyed
13011/// against the registered `CustomResourceDefinition`, so drift on the
13012/// kind axis is exactly as load-bearing as drift on the apiVersion axis
13013/// it accompanies (the apiserver's `RESTMapper` consults both together;
13014/// a `("gateway.networking.k8s.io/v1", "HTTPRout")` typo at the
13015/// production-code call site lands outside the registered Gateway-API-
13016/// conformant `HTTPRoute` CRD's `RESTKind` lookup, surfacing apply-side
13017/// as a non-self-locating "no kind 'HTTPRout' is registered for version
13018/// 'gateway.networking.k8s.io/v1'" error far from the source caixa.lisp /
13019/// the renderer's [`kube_resource_skeleton`] call site).
13020///
13021/// The single source of truth the rendered Aplicacao Gateway-API-side
13022/// ingress bundle's `HTTPRoute`-naming axis reaches for:
13023///
13024///   - the rendered `HTTPRoute` document's top-level [`KUBE_KEY_KIND`]
13025///     axis (caixa-mesh/src/lib.rs:663 — the `gateway_routes` per-
13026///     Aplicacao `HTTPRoute` [`kube_resource_skeleton`] kind argument).
13027///
13028/// The kind axis names the same Gateway-API-conformant CRD discriminator
13029/// as the sibling [`GATEWAY_API_API_VERSION`] apiVersion axis and the
13030/// peer [`GATEWAY_API_KIND_GATEWAY`] parent-Gateway axis, and must move
13031/// together with both on any future Gateway-API rebrand. Until this lift
13032/// landed the axis carried an inline `HTTPRoute` literal at the one
13033/// production-code occurrence in caixa-mesh/src/lib.rs:663 (the
13034/// `gateway_routes` `HTTPRoute` [`kube_resource_skeleton`] kind argument)
13035/// plus a matching set inside the in-file
13036/// `httproute_carries_canonical_kube_skeleton_without_labels` /
13037/// `render_all_includes_every_artifact_kind` test fixtures plus the
13038/// `find()` predicate of every per-HTTPRoute-kind test that picks the
13039/// `HTTPRoute` document out of the rendered Aplicacao mesh bundle —
13040/// multiple occurrences of the same load-bearing Gateway-API-CRD-`kind`-
13041/// discriminator convention, drift-prone by construction.
13042///
13043/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13044/// "every recurring shape becomes a generator before it becomes a
13045/// pattern; every pattern becomes a library before it becomes
13046/// duplicated code. The duplication budget is zero.") promotes the
13047/// constant to a typed substrate-side `&'static str` on the same
13048/// trajectory the [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) /
13049/// [`CILIUM_KIND_NETWORK_POLICY`] (eac85cb) /
13050/// [`FLUX_KIND_KUSTOMIZATION`] (4114773) /
13051/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
13052/// [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
13053/// [`GATEWAY_API_API_VERSION`] (3c6cfc3) lifts established on the
13054/// sibling cluster-side-CRD-`kind`-discriminator + canonical-CRD-
13055/// group/version axes — completes the per-Gateway-API-CRD `kind`-axis
13056/// lift trajectory across the `(Gateway, HTTPRoute)` pair that the
13057/// renderer's `gateway_routes` external `:entrada` ingress contract
13058/// emits together. Every guarantee in [MESH-COMPOSITION.md §V][mc] —
13059/// "every Aplicacao with `:entrada` emits one `Gateway` + one
13060/// `HTTPRoute` per `:paths` entry pointing at the same
13061/// `gateway.networking.k8s.io/v1` group/version — now threads through
13062/// one lifted `&'static str` apiece for both halves of the pair, so a
13063/// future Gateway-API rebrand lands at one substrate-side edit-point
13064/// per axis and no per-renderer drift surface remains across the pair.
13065///
13066/// A future Gateway-API-side renderer the M3.x absorption roadmap
13067/// names — `TCPRoute`, `TLSRoute`, `GRPCRoute` for non-HTTP `:entrada`
13068/// edges, the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
13069/// materializer's per-Aplicacao `HTTPRoute` fan-out, a future per-edge
13070/// route-attached-policy renderer (`BackendTLSPolicy`,
13071/// `BackendLBPolicy`) — inherits the canonical `HTTPRoute` kind
13072/// discriminator by construction with no opportunity for per-renderer
13073/// drift.
13074///
13075/// [mc]: https://github.com/pleme-io/theory/blob/main/MESH-COMPOSITION.md
13076/// [cm]: ../../caixa_mesh/index.html
13077pub const GATEWAY_API_KIND_HTTP_ROUTE: &str = "HTTPRoute";
13078
13079/// Canonical K8s Gateway API `Gateway.spec.listeners[].protocol` HTTP
13080/// listener-protocol scalar value the rendered `Gateway` document's
13081/// first (and V0-only) listener declares under its
13082/// [`KUBE_KEY_PROTOCOL`] axis. Pairs with the sibling
13083/// [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) +
13084/// [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) — the K8s Gateway API v1
13085/// CRD schema pins the per-listener L7 parser + TLS-termination
13086/// strategy through the `spec.listeners[].protocol` scalar value (the
13087/// gateway-class-controller's per-listener bind loop selects the L7
13088/// parser + TLS termination strategy from this exact byte-sequence;
13089/// the Gateway API v1 `ProtocolType` OpenAPI schema enum admits the
13090/// closed set `{"HTTP", "HTTPS", "TCP", "TLS", "UDP"}` verbatim), so
13091/// drift on the listener-protocol value is exactly as load-bearing as
13092/// drift on the sibling [`GATEWAY_API_KIND_GATEWAY`] +
13093/// [`GATEWAY_API_KIND_HTTP_ROUTE`] CRD `kind` discriminators the pair
13094/// declares together (a `("Gateway", "http")` /
13095/// `("Gateway", "Http")` / `("Gateway", "http/1.1")` typo at the
13096/// production-code call site lands outside the Gateway API v1
13097/// `ProtocolType` OpenAPI schema enum, surfacing apply-side as a
13098/// non-self-locating "spec.listeners[0].protocol: Unsupported value:
13099/// \"http\": supported values: \"HTTP\", \"HTTPS\", \"TCP\", \"TLS\",
13100/// \"UDP\"" apiserver admission-rejection far from the source
13101/// `caixa.lisp` / the renderer's `listener.insert(…)` call site — the
13102/// rendered per-Aplicacao `Gateway` object never reconciles at the
13103/// gateway-class-controller's per-listener bind loop and every
13104/// external `:entrada` HTTP flow drops at the gateway-class-
13105/// controller's admission gate with no field naming the
13106/// listener-protocol-drift root cause).
13107///
13108/// The single source of truth the rendered Aplicacao Gateway-API-side
13109/// ingress bundle's per-listener L7-parser-selection axis reaches for:
13110///
13111///   - the rendered `Gateway` document's `spec.listeners[0].protocol`
13112///     axis (the `gateway_routes` per-`:entrada` `Gateway` emitter's
13113///     `listener.insert(KUBE_KEY_PROTOCOL, "HTTP")` call — the sole
13114///     production-code call site the prior inline `"HTTP".into()`
13115///     literal sat at, caixa-mesh/src/lib.rs:2123).
13116///
13117/// The listener-protocol value names the same Gateway-API-
13118/// implementation-side per-listener L7-parser-selection scalar as the
13119/// sibling [`KUBE_KEY_PROTOCOL`] key-axis discriminator carries the
13120/// value under, and must move together with the sibling K8s Gateway
13121/// API `ProtocolType` OpenAPI schema enum on any future Gateway API
13122/// rebrand (an upstream Gateway API v2 rename of the HTTP listener
13123/// protocol from `HTTP` to `HTTP/1.1` / `HTTP/2` / `http`, coordinated
13124/// with the upstream SIG-Network Gateway API `ProtocolType` enum
13125/// deprecation cycle, would land at this one const rather than
13126/// scattered across every per-emitter listener-block-insertion site).
13127///
13128/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13129/// "every recurring shape becomes a generator before it becomes a
13130/// pattern; every pattern becomes a library before it becomes
13131/// duplicated code. The duplication budget is zero.") promotes the
13132/// constant to a typed substrate-side `&'static str` on the same
13133/// trajectory the [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) /
13134/// [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) /
13135/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) lifts established on the
13136/// sibling Gateway-API-CRD-`kind`-discriminator + Gateway-controller-
13137/// binding-scalar-value axes — extends the per-Gateway-API-CRD-`kind`-
13138/// discriminator lift pair across the `(Gateway, HTTPRoute)` pair
13139/// onto the sibling per-Gateway `spec.listeners[].protocol`
13140/// listener-protocol-scalar-value axis the same `gateway_routes`
13141/// external `:entrada` ingress emitter carries.
13142///
13143/// A future Gateway-API-side renderer the M3.x absorption roadmap
13144/// names — an HTTPS listener with TLS termination (a sibling
13145/// `GATEWAY_API_PROTOCOL_HTTPS` const value the same enum admits),
13146/// the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` materializer's
13147/// per-Aplicacao multi-listener fan-out over `{HTTP, HTTPS, TLS}`,
13148/// a future per-listener route-attached-policy renderer that binds
13149/// distinct policy chains per listener-protocol — inherits the
13150/// canonical `HTTP` listener-protocol value by construction with no
13151/// opportunity for per-renderer drift.
13152///
13153/// [cm]: ../../caixa_mesh/index.html
13154pub const GATEWAY_API_PROTOCOL_HTTP: &str = "HTTP";
13155
13156/// Canonical K8s Gateway API v1 `PathMatchType` OpenAPI schema enum's
13157/// `PathPrefix` per-`HTTPRouteMatch` path-selection-predicate discriminator
13158/// value every `gateway_routes`-emitted `HTTPRoute` per-rule `matches[]`
13159/// entry declares under its per-match `spec.rules[].matches[].path.type`
13160/// scalar axis. Pairs with the sibling [`GATEWAY_API_KEY_PATH`] (9f45aa4)
13161/// per-`HTTPRouteMatch` path-matcher container-axis key it nests one level
13162/// beneath — the Gateway API v1 CRD schema pins per-`HTTPRouteMatch`
13163/// request-path selection through the `spec.rules[].matches[].path`
13164/// container axis (each match entry names one path-selection predicate the
13165/// request line's `:path` pseudo-header must satisfy under a `type`
13166/// discriminator scalar value; the Gateway API v1 `PathMatchType` OpenAPI
13167/// schema enum admits the closed set `{"Exact", "PathPrefix",
13168/// "RegularExpression"}` verbatim), so drift on the path-match-type value
13169/// is exactly as load-bearing as drift on the sibling
13170/// [`GATEWAY_API_PROTOCOL_HTTP`] (1b57473) per-listener L7-parser-selection
13171/// scalar value the peer `spec.listeners[].protocol` axis carries (a
13172/// `"pathPrefix"` / `"path_prefix"` / `"Prefix"` / `"path-prefix"` typo at
13173/// the production-code call site lands outside the Gateway API v1
13174/// `PathMatchType` OpenAPI schema enum's admitted set, surfacing apply-side
13175/// as a non-self-locating "spec.rules[0].matches[0].path.type: Unsupported
13176/// value: \"pathPrefix\": supported values: \"Exact\", \"PathPrefix\",
13177/// \"RegularExpression\"" apiserver admission-rejection far from the
13178/// source `caixa.lisp` / the renderer's `path_match.insert(…)` call site —
13179/// the rendered per-Aplicacao `HTTPRoute` object never reconciles at the
13180/// gateway-class-controller's per-rule L7 dispatch loop and every external
13181/// `:entrada` path-filtered flow drops at the gateway-class-controller's
13182/// admission gate with no field naming the path-match-type-drift root
13183/// cause).
13184///
13185/// The single source of truth the rendered Aplicacao Gateway-API-side
13186/// ingress bundle's per-`HTTPRouteMatch` path-selection-predicate-
13187/// discriminator-value-naming reaches for:
13188///
13189///   - the rendered `HTTPRoute` document's per-match
13190///     `spec.rules[].matches[].path.type` axis (caixa-mesh/src/lib.rs —
13191///     the `gateway_routes` per-match `path_match.insert("type",
13192///     "PathPrefix")` call the prior inline `"PathPrefix".into()` literal
13193///     sat at).
13194///
13195/// The path-match-type value names the same Gateway-API-implementation-
13196/// side per-`HTTPRouteMatch` request-path-selection-predicate discriminator
13197/// as the sibling [`GATEWAY_API_KEY_PATH`] path-matcher container-axis key
13198/// carries the value under, and must move together with the sibling K8s
13199/// Gateway API v1 `PathMatchType` OpenAPI schema enum on any future
13200/// Gateway API rebrand (an upstream Gateway API v2 rename of the prefix-
13201/// path-selection discriminator from `PathPrefix` to `Prefix` / `path-
13202/// prefix` / `PathPrefixMatch`, coordinated with the upstream SIG-Network
13203/// Gateway API `PathMatchType` enum deprecation cycle, would land at this
13204/// one const rather than scattered across every per-emitter per-match
13205/// path-block-insertion site).
13206///
13207/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13208/// "every recurring shape becomes a generator before it becomes a
13209/// pattern; every pattern becomes a library before it becomes
13210/// duplicated code. The duplication budget is zero.") promotes the
13211/// constant to a typed substrate-side `&'static str` on the same
13212/// trajectory the [`GATEWAY_API_PROTOCOL_HTTP`] (1b57473) /
13213/// [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) /
13214/// [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) /
13215/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) lifts established on the
13216/// sibling per-listener L7-parser-selection scalar-value +
13217/// Gateway-API-CRD-`kind`-discriminator + Gateway-controller-binding
13218/// scalar-value axes — extends the canonical-Gateway-API-v1-OpenAPI-
13219/// schema-enum-value single-sourcing discipline the `ProtocolType.HTTP`
13220/// lift established onto the sibling `PathMatchType.PathPrefix`
13221/// per-`HTTPRouteMatch` path-selection-predicate discriminator the same
13222/// `gateway_routes` external `:entrada` ingress emitter carries under
13223/// the shared `HTTPRoute` body.
13224///
13225/// A future Gateway-API-side renderer the M3.x absorption roadmap
13226/// names — a sibling `GATEWAY_API_PATH_MATCH_TYPE_EXACT` /
13227/// `GATEWAY_API_PATH_MATCH_TYPE_REGULAR_EXPRESSION` const value the same
13228/// `PathMatchType` enum admits, the future M4
13229/// `mesh.pleme.io/v1alpha1/Aplicacao` materializer's per-Aplicacao
13230/// multi-predicate fan-out over `{Exact, PathPrefix, RegularExpression}`,
13231/// a future per-match `:entrada :paths` typed slot admitting a per-path
13232/// `(:predicate <Exact|Prefix|Regex>)` axis — inherits the canonical
13233/// `PathPrefix` path-match-type value by construction with no opportunity
13234/// for per-renderer drift.
13235///
13236/// [cm]: ../../caixa_mesh/index.html
13237pub const GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX: &str = "PathPrefix";
13238
13239/// Canonical K8s core `Protocol` OpenAPI schema enum's `TCP` L4-transport-
13240/// protocol scalar value every `cilium_network_policies`-emitted
13241/// `CiliumNetworkPolicy` document's per-`spec.ingress[].toPorts[].ports[]`
13242/// port-tuple declares under its per-tuple [`KUBE_KEY_PROTOCOL`] axis.
13243/// Pairs with the sibling [`KUBE_KEY_PROTOCOL`] (0307950) per-CR L4/L7
13244/// protocol-scalar-discriminator container-axis key the value nests
13245/// directly under — the K8s core `Protocol` schema pins per-`ContainerPort`
13246/// / `ServicePort` / `EndpointPort` / `NetworkPolicyPort` L4-transport
13247/// selection through the `protocol` scalar (each port entry names one
13248/// L4-transport-protocol discriminator the CNI / kube-proxy / eBPF-data-
13249/// plane bpf policy dispatch loop keys off before applying the port match;
13250/// the K8s core `Protocol` OpenAPI schema enum admits the closed set
13251/// `{"TCP", "UDP", "SCTP"}` verbatim — see
13252/// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1/#protocol-v1-core),
13253/// so drift on the L4-transport-protocol value is exactly as load-bearing
13254/// as drift on the sibling [`GATEWAY_API_PROTOCOL_HTTP`] (1b57473) per-
13255/// listener L7-parser-selection scalar value the peer Gateway-API v1
13256/// `ProtocolType` OpenAPI schema enum admits under the same
13257/// [`KUBE_KEY_PROTOCOL`] container-axis key (a `"tcp"` / `"Tcp"` /
13258/// `"TCP/IP"` / `"transport-tcp"` typo at the production-code call site
13259/// lands outside the K8s core `Protocol` OpenAPI schema enum's admitted
13260/// set, surfacing apply-side as a non-self-locating
13261/// "spec.ingress[0].toPorts[0].ports[0].protocol: Unsupported value:
13262/// \"tcp\": supported values: \"SCTP\", \"TCP\", \"UDP\"" apiserver
13263/// admission-rejection far from the source `caixa.lisp` / the renderer's
13264/// `port_entry.insert(…)` call site — the rendered per-`(:de, :para)`
13265/// `CiliumNetworkPolicy` object never reconciles at the Cilium operator's
13266/// per-CNP L4 dispatch pass and every intra-mesh `:contratos` L4-tuple-
13267/// gated flow drops at the Cilium operator's admission gate with no field
13268/// naming the L4-transport-protocol-drift root cause; worse — because the
13269/// `protocol` scalar carries a schema-side default of `TCP` on the K8s
13270/// core `Protocol` enum, a silently-elided drift on the emit lands a
13271/// `CiliumNetworkPolicy` whose ingress rule falls back to the default L4-
13272/// transport-protocol and every port-match on a non-default transport
13273/// silently misses at the eBPF data plane's per-tuple dispatch).
13274///
13275/// The single source of truth the rendered Aplicacao Cilium-CNP-side
13276/// intra-mesh L4-tuple-gating bundle's per-`toPorts[].ports[]` port-tuple
13277/// L4-transport-protocol-discriminator-value-naming reaches for:
13278///
13279///   - the rendered `CiliumNetworkPolicy` document's per-tuple
13280///     `spec.ingress[].toPorts[].ports[].protocol` axis (caixa-mesh/src/lib.rs —
13281///     the `cilium_network_policies` per-`(:de, :para)`
13282///     `port_entry.insert(KUBE_KEY_PROTOCOL, "TCP")` call the prior
13283///     inline `"TCP".into()` literal sat at).
13284///
13285/// The L4-transport-protocol value names the same K8s-core-`Protocol`-
13286/// enum-side per-port-tuple L4-transport-selection discriminator as the
13287/// sibling [`KUBE_KEY_PROTOCOL`] key-axis discriminator carries the value
13288/// under, and must move together with the sibling K8s core `Protocol`
13289/// OpenAPI schema enum on any future K8s core `Protocol` rebrand (an
13290/// upstream K8s core `Protocol` rename or extension — e.g. the
13291/// `KEP-3675 QUIC transport` proposal's `"QUIC"` addition to the enum,
13292/// coordinated with the upstream SIG-Network per-version deprecation
13293/// cycle — would land at this one const rather than scattered across
13294/// every per-emitter L4-port-block-insertion site).
13295///
13296/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13297/// "every recurring shape becomes a generator before it becomes a
13298/// pattern; every pattern becomes a library before it becomes
13299/// duplicated code. The duplication budget is zero.") promotes the
13300/// constant to a typed substrate-side `&'static str` on the same
13301/// trajectory the [`GATEWAY_API_PROTOCOL_HTTP`] (1b57473) /
13302/// [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`] (530705d) /
13303/// [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) /
13304/// [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) /
13305/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) lifts established on the
13306/// sibling per-listener L7-parser-selection scalar-value + per-match
13307/// path-selection-predicate discriminator-value + Gateway-API-CRD-
13308/// `kind`-discriminator + Gateway-controller-binding scalar-value axes —
13309/// extends the canonical-cluster-side-OpenAPI-schema-enum-value single-
13310/// sourcing discipline the Gateway-API v1 `ProtocolType.HTTP` /
13311/// `PathMatchType.PathPrefix` lifts established onto the sibling
13312/// K8s-core `Protocol.TCP` per-port-tuple L4-transport-protocol-
13313/// discriminator the `cilium_network_policies` intra-mesh L4-tuple-gating
13314/// emitter carries under the shared `CiliumNetworkPolicy` body.
13315///
13316/// A future Cilium-CNP-side / K8s-core-`Protocol`-side renderer the M3.x
13317/// absorption roadmap names — a sibling `KUBE_PROTOCOL_UDP` /
13318/// `KUBE_PROTOCOL_SCTP` const value the same `Protocol` enum admits, the
13319/// future M4 `mesh.pleme.io/v1alpha1/Aplicacao` materializer's per-
13320/// Aplicacao multi-transport fan-out over `{TCP, UDP, SCTP}` for
13321/// `nats:pub-sub` / `wasi:sockets/udp` contratos, a future per-contrato
13322/// `:transport <TCP|UDP|SCTP>` typed slot admitting a per-edge transport-
13323/// protocol axis — inherits the canonical `TCP` L4-transport-protocol
13324/// value by construction with no opportunity for per-renderer drift.
13325///
13326/// [cm]: ../../caixa_mesh/index.html
13327pub const KUBE_PROTOCOL_TCP: &str = "TCP";
13328
13329/// Canonical Cilium `CiliumNetworkPolicy` `MutualAuthenticationMode` OpenAPI
13330/// schema enum's `required` per-`ingress[].authentication.mode` mTLS-mandatory
13331/// scalar-value every `cilium_network_policies`-emitted CNP document declares
13332/// under its per-rule mutual-auth-mode-discriminator leaf axis when the typed
13333/// `:politicas :mtls-required` tristate is `Some(true)`. Pairs with the sibling
13334/// [`CILIUM_KEY_MODE`] (4289dfb) per-authn-block mode-discriminator leaf-axis
13335/// key the value nests directly under, and the sibling
13336/// [`CILIUM_AUTH_MODE_DISABLED`] scalar-value the `Some(false)` opt-out arm of
13337/// the same tristate emits — the Cilium CNP `MutualAuthenticationMode` OpenAPI
13338/// schema enum admits the closed set `{"required", "disabled", "test-always-
13339/// fail"}` verbatim (the `test-always-fail` arm is an infrastructure-side
13340/// debugging surface, not an author-reachable slot), so drift on the mTLS-
13341/// mandatory scalar-value is exactly as load-bearing as drift on the sibling
13342/// per-authn-block mode-discriminator leaf axis it nests under (a `"Required"`
13343/// / `"REQUIRED"` / `"mandatory"` / `"mtls-required"` typo at either the
13344/// production-code call site or a downstream probe lands outside the Cilium
13345/// CNP `MutualAuthenticationMode` OpenAPI schema enum's admitted set,
13346/// surfacing apply-side as a Cilium-agent per-rule mutual-auth-block schema-
13347/// validator drop far from the source `caixa.lisp` / the renderer's
13348/// `single_field_overlay(mtls_required, CILIUM_KEY_MODE, …)` call site — the
13349/// rendered per-`(:de, :para)` `CiliumNetworkPolicy` object never enforces
13350/// per-edge SPIFFE-identity-bound mutual-auth at the Cilium data-plane's per-
13351/// rule handshake gate and every intra-mesh `:contratos` flow the CNP was
13352/// authored to protect with per-edge mTLS silently bypasses the handshake at
13353/// the Cilium data-plane's default-authentication mode with no field naming
13354/// the mTLS-mandatory-scalar-value-drift root cause).
13355///
13356/// The single source of truth the rendered Aplicacao Cilium-CNP-side per-edge
13357/// mutual-auth-mode-discriminator affirmative-value-naming reaches for:
13358///
13359///   - the rendered `CiliumNetworkPolicy` document's per-rule
13360///     `spec.ingress[].authentication.mode` leaf value (caixa-mesh/src/lib.rs
13361///     — the `cilium_network_policies` per-`(:de, :para)`
13362///     `single_field_overlay(spec.politicas.mtls_required, CILIUM_KEY_MODE,
13363///     |required| …)` closure's `if required { … }` arm the prior inline
13364///     `"required".into()` literal sat at, plus every test-fixture navigation
13365///     that pins the emitted value under the `:mtls-required t` presence,
13366///     fan-out, and pubsub-carry-overlay-too shapes).
13367///
13368/// The mTLS-mandatory scalar-value names the same Cilium-agent-side per-rule
13369/// SPIFFE-identity-handshake-mandatory enforcement policy as the sibling
13370/// [`CILIUM_KEY_MODE`] leaf-axis key carries the value under, and must move
13371/// together with the sibling Cilium CNP `MutualAuthenticationMode` OpenAPI
13372/// schema enum on any future Cilium CRD schema rebrand (an upstream
13373/// `cilium.io/v3` rename of the mTLS-mandatory scalar-value from `required`
13374/// to `enforce` / `mandatory` / `strict`, coordinated with the Cilium
13375/// project's periodic CRD schema-migration passes, would land at this one
13376/// const rather than scattered across every per-emitter per-rule authn-block-
13377/// insertion site).
13378///
13379/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
13380/// recurring shape becomes a generator before it becomes a pattern; every
13381/// pattern becomes a library before it becomes duplicated code. The
13382/// duplication budget is zero.") promotes the constant to a typed substrate-
13383/// side `&'static str` on the same trajectory the
13384/// [`GATEWAY_API_PROTOCOL_HTTP`] (1b57473) /
13385/// [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`] (530705d) /
13386/// [`KUBE_PROTOCOL_TCP`] (2123047) scalar-value lifts established on the
13387/// sibling canonical-cluster-side-OpenAPI-schema-enum-value surfaces —
13388/// extends the canonical-cluster-side-OpenAPI-schema-enum-value single-
13389/// sourcing discipline the Gateway-API v1 `ProtocolType.HTTP` /
13390/// `PathMatchType.PathPrefix` / K8s-core `Protocol.TCP` lifts established
13391/// onto the sibling Cilium-CNP-side `MutualAuthenticationMode.required`
13392/// per-rule mTLS-mandatory scalar-value the `cilium_network_policies` per-
13393/// edge SPIFFE-identity-bound mutual-auth emitter carries under the shared
13394/// `CiliumNetworkPolicy` body.
13395///
13396/// [cm]: ../../caixa_mesh/index.html
13397pub const CILIUM_AUTH_MODE_REQUIRED: &str = "required";
13398
13399/// Canonical Cilium `CiliumNetworkPolicy` `MutualAuthenticationMode` OpenAPI
13400/// schema enum's `disabled` per-`ingress[].authentication.mode` mTLS-skipped
13401/// scalar-value every `cilium_network_policies`-emitted CNP document declares
13402/// under its per-rule mutual-auth-mode-discriminator leaf axis when the typed
13403/// `:politicas :mtls-required` tristate is the explicit `Some(false)` opt-out
13404/// arm (an author who *named* the axis and asked for the mTLS handshake to be
13405/// skipped on this Aplicacao's edges — e.g. a debug or legacy-bridge
13406/// Aplicacao that needs to talk to non-mesh peers, distinct from the `None`
13407/// slot-absent arm the renderer maps to omit-the-block-entirely). Peer to
13408/// the sibling [`CILIUM_AUTH_MODE_REQUIRED`] mTLS-mandatory scalar-value the
13409/// `Some(true)` affirmative arm emits under the same tristate branch — the
13410/// Cilium CNP `MutualAuthenticationMode` OpenAPI schema enum admits the two
13411/// arms as a matched author-reachable pair.
13412///
13413/// The single source of truth the rendered Aplicacao Cilium-CNP-side per-edge
13414/// mutual-auth-mode-discriminator negative-value-naming reaches for:
13415///
13416///   - the rendered `CiliumNetworkPolicy` document's per-rule
13417///     `spec.ingress[].authentication.mode` leaf value (caixa-mesh/src/lib.rs
13418///     — the `cilium_network_policies` per-`(:de, :para)`
13419///     `single_field_overlay(spec.politicas.mtls_required, CILIUM_KEY_MODE,
13420///     |required| …)` closure's `else { … }` arm the prior inline
13421///     `"disabled".into()` literal sat at, plus the
13422///     `cnp_explicit_mtls_required_false_emits_disabled_mode` test-fixture
13423///     probe that pins the explicit-opt-out arm's rendered value).
13424///
13425/// Same drift-mode risk as the sibling [`CILIUM_AUTH_MODE_REQUIRED`] pin: a
13426/// `"Disabled"` / `"DISABLED"` / `"off"` / `"skip"` typo lands outside the
13427/// Cilium CNP `MutualAuthenticationMode` OpenAPI schema enum's admitted set;
13428/// the rendered per-`(:de, :para)` `CiliumNetworkPolicy` object never reaches
13429/// the Cilium agent's per-rule mutual-auth-block schema validator's admitted
13430/// set and the author's explicit-opt-out intent silently collapses onto the
13431/// cluster-default authentication mode (typically also "disabled" today, but
13432/// environment-divergent — take effect) with no field naming the mTLS-
13433/// skipped-scalar-value-drift root cause.
13434///
13435/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
13436/// recurring shape becomes a generator before it becomes a pattern; every
13437/// pattern becomes a library before it becomes duplicated code. The
13438/// duplication budget is zero.") promotes the constant to a typed substrate-
13439/// side `&'static str` on the same trajectory the sibling
13440/// [`CILIUM_AUTH_MODE_REQUIRED`] mTLS-mandatory scalar-value lift establishes
13441/// on the affirmative arm of the same `MutualAuthenticationMode` enum —
13442/// completes the per-authn-block `(mode → {required, disabled})` leaf-axis /
13443/// author-reachable-scalar-value-pair single-sourcing the M3 Aplicacao mesh
13444/// renderer's SPIFFE-identity-bound per-edge mTLS enforcement + explicit-
13445/// opt-out contract rests on across the two arms of the `:politicas
13446/// :mtls-required` tristate.
13447///
13448/// [cm]: ../../caixa_mesh/index.html
13449pub const CILIUM_AUTH_MODE_DISABLED: &str = "disabled";
13450
13451/// Canonical `bool → &'static str` bijection projection every consumer of the
13452/// Cilium `CiliumNetworkPolicy` `MutualAuthenticationMode` OpenAPI schema
13453/// enum's closed-set author-reachable scalar-value pair
13454/// ([`CILIUM_AUTH_MODE_REQUIRED`] / [`CILIUM_AUTH_MODE_DISABLED`]) consults
13455/// so the per-tristate-arm dispatch — `Some(true)` (mTLS handshake
13456/// mandatory) → [`CILIUM_AUTH_MODE_REQUIRED`], `Some(false)` (mTLS
13457/// handshake skipped, explicit opt-out) → [`CILIUM_AUTH_MODE_DISABLED`] —
13458/// lives in exactly one place. The two arms of the `:politicas
13459/// :mtls-required` tristate's non-`None` value-space each land on a
13460/// distinct `MutualAuthenticationMode` scalar; the `None` slot-absent arm
13461/// is the caller's [`single_field_overlay`] emission-gate concern (the
13462/// helper returns `None` and the outer `authentication:` block is omitted
13463/// entirely), not this projection's — see the per-emit-site
13464/// `if let Some(overlay) = mtls_overlay { rule.insert(CILIUM_KEY_AUTHENTICATION,
13465/// overlay.clone()) }` guard.
13466///
13467/// The single source of truth the rendered Aplicacao Cilium-CNP-side
13468/// per-edge mutual-auth-mode-discriminator scalar-value dispatch reaches
13469/// for:
13470///
13471///   - the rendered `CiliumNetworkPolicy` document's per-rule
13472///     `spec.ingress[].authentication.mode` leaf value (caixa-mesh/src/lib.rs
13473///     — the `cilium_network_policies` per-`(:de, :para)`
13474///     `single_field_overlay(spec.politicas.mtls_required, CILIUM_KEY_MODE,
13475///     |required| serde_yaml::Value::String(cilium_auth_mode(required).into()))`
13476///     closure body).
13477///   - the generic-helper pin in this crate's
13478///     `single_field_overlay_threads_typed_value_through_closure` test
13479///     that mirrors the production overlay's shape letter-for-letter and
13480///     now threads through the same shared projection.
13481///
13482/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
13483/// recurring shape becomes a generator before it becomes a pattern; every
13484/// pattern becomes a library before it becomes duplicated code. The
13485/// duplication budget is zero.") promotes the per-tristate-arm dispatch
13486/// body onto a shared projection on the same trajectory the sibling
13487/// [`CILIUM_AUTH_MODE_REQUIRED`] / [`CILIUM_AUTH_MODE_DISABLED`]
13488/// closed-set-scalar-value lifts established for the two arms of the
13489/// same `MutualAuthenticationMode` enum — closes the pair of related
13490/// lift trajectories the `(value-space, arm-dispatch)` per-authn-block
13491/// leaf's canonical decomposition rests on. The prior inline `if required
13492/// { CILIUM_AUTH_MODE_REQUIRED } else { CILIUM_AUTH_MODE_DISABLED }` body
13493/// split across the two occurrences — the caixa-mesh production emitter's
13494/// closure and the caixa-core generic-helper pin's closure — would have
13495/// let a per-arm reassignment (e.g. an upstream Cilium v3 schema rename
13496/// swap of the `required` ↔ `disabled` scalars, or the addition of a
13497/// third `MutualAuthenticationMode` variant that reshapes the closed set)
13498/// drift on one closure body but not the peer, silently letting a Cilium
13499/// data-plane pod either enforce mTLS where the author asked for skip or
13500/// skip it where the author asked for enforce.
13501///
13502/// Pairs with the [`CILIUM_KEY_MODE`] per-authentication-block mode-
13503/// discriminator leaf-axis key at the caller's
13504/// `single_field_overlay(spec.politicas.mtls_required, CILIUM_KEY_MODE,
13505/// |required| serde_yaml::Value::String(cilium_auth_mode(required).into()))`
13506/// call: the key is the field name the leaf mounts under, this projection
13507/// is the scalar the leaf carries. Same-shape peer to the K8s core
13508/// `Protocol` closed-set enum's future `bool → {"TCP", "UDP"}` /
13509/// K8s Gateway API v1 `PathMatchType` closed-set enum's future variant-
13510/// pick projections the M3.x absorption roadmap acknowledges — the M3
13511/// mesh renderer's `MutualAuthenticationMode` bijection surface is the
13512/// first landed instance of the canonical `(closed-set-CRD-schema-enum-
13513/// value pair, per-typed-arm dispatch projection)` compound.
13514///
13515/// [cm]: ../../caixa_mesh/index.html
13516#[must_use]
13517pub fn cilium_auth_mode(required: bool) -> &'static str {
13518    if required {
13519        CILIUM_AUTH_MODE_REQUIRED
13520    } else {
13521        CILIUM_AUTH_MODE_DISABLED
13522    }
13523}
13524
13525/// Canonical K8s Gateway API `HTTPRoute` parent-Gateway-binding container-
13526/// axis key every `gateway_routes`-emitted `HTTPRoute` document mounts its
13527/// per-route parent-Gateway `[{name}]` list under (`spec.parentRefs[]`).
13528/// Pairs with the sibling [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) +
13529/// [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) — the Gateway API v1 CRD schema
13530/// pins the per-HTTPRoute parent-Gateway identity through the
13531/// `spec.parentRefs[]` container axis (each entry names the parent
13532/// Gateway the route attaches to; the sibling `hostnames` + `rules`
13533/// container axes carry the per-route host-match + per-rule L7-dispatch
13534/// halves under the same `spec` block), so drift on the parent-Gateway-
13535/// binding axis is exactly as load-bearing as drift on the per-HTTPRoute
13536/// `kind` discriminator axis it accompanies (the K8s apiserver-side
13537/// Gateway API CRD schema validator drops any `spec` block whose parent-
13538/// binding container axis carries an unrecognized key — a `"parentRef"`
13539/// / `"parents"` / `"parentGateways"` typo silently emits an `HTTPRoute`
13540/// whose parent-Gateway attachment the Gateway API implementation's
13541/// per-HTTPRoute reconcile loop no-ops entirely: the route lands
13542/// unattached to any Gateway, and every external `:entrada` flow the
13543/// `HTTPRoute` was authored to accept drops at the Gateway API
13544/// implementation's per-Gateway HTTP-listener fan-in with no field
13545/// naming the parent-Gateway-binding-axis-drift root cause).
13546///
13547/// The single source of truth the rendered Aplicacao Gateway-API-side
13548/// ingress bundle's per-HTTPRoute parent-Gateway-binding-axis-naming
13549/// reaches for:
13550///
13551///   - the rendered `HTTPRoute` document's `spec.parentRefs[]` axis
13552///     (caixa-mesh/src/lib.rs:1389 — the `gateway_routes` per-Aplicacao
13553///     `HTTPRoute`'s `r_spec.insert("parentRefs", …)` call).
13554///
13555/// The parent-Gateway-binding axis names the same Gateway-API-
13556/// implementation-side per-HTTPRoute route→Gateway attachment container
13557/// as the sibling [`GATEWAY_API_KIND_HTTP_ROUTE`] +
13558/// [`GATEWAY_API_KIND_GATEWAY`] CRD `kind` discriminators the pair
13559/// declares together, and must move together on any future Gateway API
13560/// rebrand (an upstream Gateway API v2 rename of the parent-binding
13561/// axis from `parentRefs` to `parents` / `parentGateways` /
13562/// `attachedTo`, coordinated with the upstream SIG-Network Gateway API
13563/// deprecation cycle). Until this lift landed the axis carried an
13564/// inline `parentRefs` literal at the one production-code occurrence in
13565/// caixa-mesh/src/lib.rs:1389 (the `gateway_routes`
13566/// `r_spec.insert("parentRefs", …)` call) — the single load-bearing
13567/// Gateway-API-CRD-`parentRefs`-axis-key occurrence, drift-prone by
13568/// construction. A drift on the production site to `"parentRef"` /
13569/// `"parents"` / `"parentGateways"` would have surfaced as a Gateway-
13570/// API-implementation-side schema validator drop at apply time (the
13571/// affected `HTTPRoute`'s parent-Gateway-binding axis the CRD schema
13572/// validator recognizes as unknown), with every external `:entrada`
13573/// flow the `HTTPRoute` was authored to accept dropping at the Gateway
13574/// API implementation's per-Gateway HTTP-listener fan-in with no field
13575/// naming the parent-Gateway-binding-drift root cause.
13576///
13577/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13578/// "every recurring shape becomes a generator before it becomes a
13579/// pattern; every pattern becomes a library before it becomes
13580/// duplicated code. The duplication budget is zero.") promotes the
13581/// constant to a typed substrate-side `&'static str` on the same
13582/// trajectory the [`CILIUM_KEY_PORTS`] (1087693) /
13583/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
13584/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
13585/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
13586/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
13587/// [`KUBE_KEY_RULES`] (a205eb3) /
13588/// [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) /
13589/// [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) lifts established on the
13590/// sibling canonical-Cilium-CNP-body-axis /
13591/// canonical-Gateway-API-CRD-`kind`-discriminator surfaces — pivots the
13592/// per-CNP-body-axis lift discipline onto the sibling per-HTTPRoute-
13593/// body-axis surface, beginning the per-Gateway-API-HTTPRoute-body-axis
13594/// canonical-string-pin set (`parentRefs`, `hostnames`) the M3
13595/// Aplicacao mesh renderer's external `:entrada` ingress contract rests
13596/// on across the Gateway API HTTPRoute-side per-route body-shape. The
13597/// render-side consumer now threads the same `&'static str` through
13598/// its `r_spec.insert(…)` call so a future Gateway API rebrand on the
13599/// parent-Gateway-binding axis (or an upstream SIG-Network Gateway API
13600/// v2 rename to a per-CRD sibling name) lands in one place; every
13601/// future renderer that reaches for the canonical per-HTTPRoute parent-
13602/// Gateway-binding axis (the future M4
13603/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
13604/// `HTTPRoute` fan-out, a future per-edge `TCPRoute` / `TLSRoute` /
13605/// `GRPCRoute` renderer for non-HTTP `:entrada` edges whose per-route
13606/// parent-Gateway-binding nests under the same axis convention, a
13607/// future per-Aplicacao `ReferenceGrant` renderer whose cross-namespace
13608/// parent-Gateway attachment binds against this same axis) inherits the
13609/// same value by construction with no opportunity for per-renderer
13610/// drift.
13611///
13612/// Same "the typed constant lives in one place" discipline the
13613/// [`CILIUM_KEY_PORTS`] (1087693) /
13614/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
13615/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
13616/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
13617/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
13618/// [`KUBE_KEY_RULES`] (a205eb3) /
13619/// [`GATEWAY_API_KIND_HTTP_ROUTE`] (1adccc0) /
13620/// [`GATEWAY_API_KIND_GATEWAY`] (fb4639c) lifts apply on the peer
13621/// canonical-Gateway-API-HTTPRoute-body-axis surface.
13622///
13623/// [cm]: ../../caixa_mesh/index.html
13624pub const GATEWAY_API_KEY_PARENT_REFS: &str = "parentRefs";
13625
13626/// Canonical K8s Gateway API `HTTPRoute` per-`spec.parentRefs[]` entry
13627/// listener-selector sub-axis key every `gateway_routes`-emitted
13628/// `HTTPRoute` document mounts under each parent-Gateway attachment to
13629/// pin the route to one specific listener out of the parent Gateway's
13630/// `spec.listeners[]` list (`spec.parentRefs[].sectionName`). Pairs
13631/// with the sibling [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) — the
13632/// Gateway API v1 CRD schema pins per-HTTPRoute route→Gateway
13633/// attachment through the `spec.parentRefs[]` container axis and the
13634/// per-entry listener-selection sub-axis through `sectionName` beneath
13635/// each entry (each `SectionName`-typed scalar binds to a
13636/// `Gateway.spec.listeners[].name` byte-string). Omitting the
13637/// selector attaches the route to *every* listener on the parent
13638/// Gateway — the Gateway API v1 default fan-out that silently doubles
13639/// route emission once the substrate ships a second listener under
13640/// the HTTPS-by-default trajectory the peer
13641/// [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] (cd60fde) docstring
13642/// forecasts (`"http"` → `"http-v1"` alongside a sibling `"https"`
13643/// listener once cert-manager-issued per-`:entrada :host` certificates
13644/// land). Pinning the selector by construction binds each substrate-
13645/// emitted route to exactly one listener on the parent Gateway, so a
13646/// future multi-listener migration lands as one const-edit on the
13647/// paired [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] declaration
13648/// instead of a silent per-route dispatch flip.
13649///
13650/// The single source of truth the rendered Aplicacao Gateway-API-side
13651/// ingress bundle's per-HTTPRoute per-parentRef listener-selector-axis-
13652/// naming reaches for:
13653///
13654///   - the rendered `HTTPRoute` document's per-parentRef
13655///     `spec.parentRefs[].sectionName` axis (the `gateway_routes` per-
13656///     Aplicacao HTTPRoute's `parent_ref.insert(<KEY>, …)` call the
13657///     paired [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] `&'static str`
13658///     — the same byte-string the parent Gateway's sole
13659///     `listener.insert(GATEWAY_API_KEY_NAME, …)` call emits at
13660///     `spec.listeners[].name` — flows through, so a substrate-side
13661///     rebrand of the canonical listener-name identifier reaches both
13662///     the listener-name emitter and the sectionName selector by
13663///     construction).
13664///
13665/// The per-parentRef listener-selector sub-axis names the same
13666/// Gateway-API-implementation-side per-HTTPRoute route→listener
13667/// attachment sub-container as the sibling
13668/// [`GATEWAY_API_KEY_PARENT_REFS`] per-HTTPRoute parent-Gateway-binding
13669/// container axis it accompanies, and must move together on any future
13670/// Gateway API rebrand (an upstream SIG-Network Gateway API v2 rename
13671/// of the per-entry listener-selection sub-axis from `sectionName` to
13672/// `listenerName` / `listener` / `attachTo`, coordinated with the
13673/// Gateway API deprecation cycle). Until this lift landed the axis had
13674/// zero production-code call sites — the substrate emitted an
13675/// `HTTPRoute` whose `spec.parentRefs[]` entries omitted the selector
13676/// entirely, silently accepting the Gateway API v1 attach-to-every-
13677/// listener default fan-out. A future substrate-side second listener
13678/// under the same parent Gateway (the HTTPS-by-default trajectory the
13679/// [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] docstring forecasts)
13680/// would have silently doubled every route's emitted per-request
13681/// dispatch surface — every external `:entrada` request the route was
13682/// authored to accept on `:80` would have accepted a matching request
13683/// on `:443` too, with the second-listener leak surfacing only in per-
13684/// request access logs (never in `kubectl describe httproute` — the
13685/// implicit fan-out reads as intended per the Gateway API v1 spec).
13686///
13687/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13688/// "every recurring shape becomes a generator before it becomes a
13689/// pattern; every pattern becomes a library before it becomes
13690/// duplicated code. The duplication budget is zero.") promotes the
13691/// constant to a typed substrate-side `&'static str` on the same
13692/// trajectory the [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
13693/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
13694/// [`GATEWAY_API_KEY_MATCHES`] (8f9ed08) /
13695/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
13696/// [`GATEWAY_API_KEY_HOSTNAMES`] (bd7ea31) lifts established on the
13697/// sibling canonical-Gateway-API-HTTPRoute-body-axis surface — extends
13698/// the per-Gateway-API-HTTPRoute-body-axis canonical-string-pin set
13699/// onto the per-parentRef listener-selector sub-axis the M3 Aplicacao
13700/// mesh renderer's external `:entrada` ingress contract now rests on.
13701/// The render-side consumer threads the same `&'static str` through
13702/// its `parent_ref.insert(…)` call so a future Gateway API rebrand on
13703/// the per-parentRef listener-selector sub-axis (or an upstream SIG-
13704/// Network Gateway API v2 rename to a per-CRD sibling name) lands in
13705/// one place; every future renderer that reaches for the canonical
13706/// per-HTTPRoute per-parentRef listener-selector sub-axis (the future
13707/// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-
13708/// Aplicacao `HTTPRoute` fan-out, a future per-edge `TCPRoute` /
13709/// `TLSRoute` / `GRPCRoute` renderer whose per-parentRef listener-
13710/// selection nests under the same axis convention) inherits the same
13711/// value by construction with no opportunity for per-renderer drift.
13712///
13713/// Same "the typed constant lives in one place" discipline the
13714/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
13715/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
13716/// [`GATEWAY_API_KEY_MATCHES`] (8f9ed08) lifts apply on the peer
13717/// canonical-Gateway-API-HTTPRoute-body-axis surface.
13718///
13719/// [cm]: ../../caixa_mesh/index.html
13720pub const GATEWAY_API_KEY_SECTION_NAME: &str = "sectionName";
13721
13722/// Canonical K8s Gateway API `HTTPRoute` per-rule backend-destination
13723/// container-axis key every `gateway_routes`-emitted `HTTPRoute`
13724/// document mounts its per-rule `[{name, port}]` backend list under
13725/// (`spec.rules[].backendRefs[]`). Pairs with the sibling
13726/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) — the Gateway API v1 CRD
13727/// schema pins the per-HTTPRoute route→Gateway attachment through the
13728/// `spec.parentRefs[]` container axis and the per-rule route→Servico
13729/// backend fan-out through the `spec.rules[].backendRefs[]` axis
13730/// beneath each rule entry, so drift on the per-rule backend-destination
13731/// axis is exactly as load-bearing as drift on the per-HTTPRoute
13732/// parent-Gateway-binding axis it accompanies (the K8s apiserver-side
13733/// Gateway API CRD schema validator drops any per-rule block whose
13734/// backend-destination container axis carries an unrecognized key — a
13735/// `"backendRef"` / `"backends"` / `"forwardTo"` typo silently emits an
13736/// `HTTPRoute` whose per-rule backend fan-out the Gateway API
13737/// implementation's per-rule L7 dispatch loop no-ops entirely: no
13738/// backend is picked, and every external `:entrada` request the rule
13739/// was authored to route drops at the gateway-class-controller's
13740/// per-rule reconcile with no field naming the backend-destination-
13741/// axis-drift root cause).
13742///
13743/// The single source of truth the rendered Aplicacao Gateway-API-side
13744/// ingress bundle's per-HTTPRoute per-rule backend-destination-axis-
13745/// naming reaches for:
13746///
13747///   - the rendered `HTTPRoute` document's per-rule
13748///     `spec.rules[].backendRefs[]` axis (caixa-mesh/src/lib.rs:1414 —
13749///     the `gateway_routes` per-Aplicacao HTTPRoute's per-rule
13750///     `rule.insert("backendRefs", …)` call).
13751///
13752/// The per-rule backend-destination container axis names the same
13753/// Gateway-API-implementation-side per-rule route→Servico backend fan-
13754/// out container as the sibling [`GATEWAY_API_KEY_PARENT_REFS`] per-
13755/// HTTPRoute parent-Gateway-binding container axis it accompanies, and
13756/// must move together on any future Gateway API rebrand (an upstream
13757/// SIG-Network Gateway API v2 rename of the backend-destination axis
13758/// from `backendRefs` to `backends` / `forwardTo` / `to`, coordinated
13759/// with the Gateway API deprecation cycle). Until this lift landed the
13760/// axis carried an inline `backendRefs` literal at the one production-
13761/// code occurrence in caixa-mesh/src/lib.rs:1414 (the `gateway_routes`
13762/// per-rule `rule.insert("backendRefs", …)` call) plus a matching set
13763/// inside the in-file `httproute_routes_to_entrada_para` /
13764/// `httproute_rule_keys_pin_overlay_position` test-fixture navigations —
13765/// three occurrences of the same load-bearing Gateway-API-CRD-
13766/// `backendRefs`-axis-key convention, drift-prone by construction. A
13767/// drift on any one production or test-fixture site to `"backendRef"` /
13768/// `"backends"` / `"forwardTo"` would have surfaced as a Gateway API
13769/// implementation-side schema validator drop at apply time (the
13770/// affected per-rule backend-destination axis the CRD schema validator
13771/// recognizes as unknown), with every external `:entrada` request the
13772/// rule was authored to route dropping at the gateway-class-
13773/// controller's per-rule reconcile with no field naming the backend-
13774/// destination-drift root cause. A drift on the test-fixture side
13775/// silently masks the emission-side pin (`.get("backendRefs")` returns
13776/// `None` under both the drifted-key emitter and the drifted-key probe
13777/// — the downstream `.and_then(|b| b.as_sequence())` /
13778/// `.and_then(|s| s.first())` chain short-circuits vacuously because
13779/// the outer per-rule backend-destination lookup is itself `None`).
13780///
13781/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13782/// "every recurring shape becomes a generator before it becomes a
13783/// pattern; every pattern becomes a library before it becomes
13784/// duplicated code. The duplication budget is zero.") promotes the
13785/// constant to a typed substrate-side `&'static str` on the same
13786/// trajectory the [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
13787/// [`CILIUM_KEY_PORTS`] (1087693) /
13788/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
13789/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
13790/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
13791/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
13792/// [`KUBE_KEY_RULES`] (a205eb3) lifts established on the sibling
13793/// canonical-Gateway-API-HTTPRoute-body-axis /
13794/// canonical-Cilium-CNP-body-axis surfaces — extends the per-Gateway-
13795/// API-HTTPRoute-body-axis canonical-string-pin set the sibling
13796/// `parentRefs` lift began (`parentRefs`, `backendRefs`, future
13797/// `hostnames`) the M3 Aplicacao mesh renderer's external `:entrada`
13798/// ingress contract rests on across the Gateway API HTTPRoute-side per-
13799/// route body-shape. The render-side consumer now threads the same
13800/// `&'static str` through its `rule.insert(…)` call so a future Gateway
13801/// API rebrand on the per-rule backend-destination axis (or an upstream
13802/// SIG-Network Gateway API v2 rename to a per-CRD sibling name) lands
13803/// in one place; every future renderer that reaches for the canonical
13804/// per-HTTPRoute per-rule backend-destination axis (the future M4
13805/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
13806/// `HTTPRoute` fan-out, a future per-edge `TCPRoute` / `TLSRoute` /
13807/// `GRPCRoute` renderer for non-HTTP `:entrada` edges whose per-rule
13808/// backend-destination nests under the same axis convention, a future
13809/// per-route mirroring / traffic-split renderer whose per-weight
13810/// backend list binds against this same axis) inherits the same value
13811/// by construction with no opportunity for per-renderer drift.
13812///
13813/// Same "the typed constant lives in one place" discipline the
13814/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
13815/// [`CILIUM_KEY_PORTS`] (1087693) /
13816/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
13817/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
13818/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
13819/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
13820/// [`KUBE_KEY_RULES`] (a205eb3) lifts apply on the peer canonical-
13821/// Gateway-API-HTTPRoute-body-axis surface.
13822///
13823/// [cm]: ../../caixa_mesh/index.html
13824pub const GATEWAY_API_KEY_BACKEND_REFS: &str = "backendRefs";
13825
13826/// Canonical K8s Gateway API `HTTPRoute` per-rule route-match
13827/// container-axis key every `gateway_routes`-emitted `HTTPRoute`
13828/// per-rule block mounts its per-rule `[{path: {type, value}}]`
13829/// route-match fan-out list under (`spec.rules[].matches[]`). Pairs
13830/// with the sibling [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) — the
13831/// Gateway API v1 CRD schema pins per-rule request-selection through
13832/// the `spec.rules[].matches[]` container axis (each entry names one
13833/// `HTTPRouteMatch` predicate the request line + headers + query must
13834/// satisfy for the rule's backend fan-out to apply) alongside the
13835/// per-rule route→Servico backend fan-out under
13836/// `spec.rules[].backendRefs[]`, so drift on the per-rule route-match
13837/// axis is exactly as load-bearing as drift on the sibling per-rule
13838/// backend-destination axis it accompanies (the K8s apiserver-side
13839/// Gateway API CRD schema validator drops any per-rule block whose
13840/// route-match container axis carries an unrecognized key — a
13841/// `"match"` / `"routeMatches"` / `"predicates"` typo silently emits
13842/// an `HTTPRoute` whose per-rule request-selection axis the Gateway
13843/// API implementation's per-rule L7 dispatch loop no-ops entirely: no
13844/// request predicate is evaluated, the rule matches every request
13845/// unconditionally at the wildcard predicate, and every external
13846/// `:entrada` path filter the rule was authored to enforce drops at
13847/// the gateway-class-controller's per-rule reconcile with no field
13848/// naming the route-match-axis-drift root cause).
13849///
13850/// The single source of truth the rendered Aplicacao Gateway-API-side
13851/// ingress bundle's per-HTTPRoute per-rule route-match-axis-naming
13852/// reaches for:
13853///
13854///   - the rendered `HTTPRoute` document's per-rule
13855///     `spec.rules[].matches[]` axis (caixa-mesh/src/lib.rs — the
13856///     `gateway_routes` per-Aplicacao HTTPRoute's per-rule
13857///     `rule.insert("matches", …)` call seeded from the Aplicacao's
13858///     `:entrada :paths` slot).
13859///
13860/// The per-rule route-match container axis names the same Gateway-
13861/// API-implementation-side per-rule request-selection predicate fan-
13862/// out container as the sibling [`GATEWAY_API_KEY_BACKEND_REFS`]
13863/// per-rule backend-destination container axis it accompanies, and
13864/// must move together on any future Gateway API rebrand (an upstream
13865/// SIG-Network Gateway API v2 rename of the route-match axis from
13866/// `matches` to `match` / `routeMatches` / `predicates`, coordinated
13867/// with the Gateway API deprecation cycle). Until this lift landed
13868/// the axis carried an inline `matches` literal at the one
13869/// production-code occurrence in caixa-mesh/src/lib.rs (the
13870/// `gateway_routes` per-rule `rule.insert("matches", …)` call) plus
13871/// a matching test-fixture navigation inside the in-file
13872/// `httproute_rule_keys_pin_overlay_position` pin's
13873/// `contains_key("matches")` presence assertion — two occurrences of
13874/// the same load-bearing Gateway-API-CRD-`matches`-axis-key
13875/// convention, drift-prone by construction. A drift on the
13876/// production site to `"match"` / `"routeMatches"` / `"predicates"`
13877/// would have surfaced as a Gateway API implementation-side schema
13878/// validator drop at apply time (the affected per-rule route-match
13879/// axis the CRD schema validator recognizes as unknown), with the
13880/// per-rule request predicate degrading to the wildcard match at the
13881/// gateway-class-controller's per-rule reconcile with no field
13882/// naming the route-match-drift root cause. A drift on the test-
13883/// fixture side silently masks the emission-side pin
13884/// (`contains_key("matches")` returns `false` under both the
13885/// drifted-key emitter and the drifted-key probe).
13886///
13887/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13888/// "every recurring shape becomes a generator before it becomes a
13889/// pattern; every pattern becomes a library before it becomes
13890/// duplicated code. The duplication budget is zero.") promotes the
13891/// constant to a typed substrate-side `&'static str` on the same
13892/// trajectory the [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
13893/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
13894/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
13895/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
13896/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
13897/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
13898/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) lifts established on the
13899/// sibling canonical-Gateway-API-HTTPRoute-body-axis surface —
13900/// completes the per-rule top-level-axis lifted-string set
13901/// (`matches`, `backendRefs`, `timeouts`, `retry`) the
13902/// `httproute_rule_keys_pin_overlay_position` pin binds against, so
13903/// every one of the four per-rule top-level axes now threads a
13904/// lifted `&'static str` apiece. The render-side consumer now
13905/// threads the same `&'static str` through its `rule.insert(…)`
13906/// call so a future Gateway API rebrand on the per-rule route-match
13907/// axis (or an upstream SIG-Network Gateway API v2 rename to a
13908/// per-CRD sibling name) lands in one place; every future renderer
13909/// that reaches for the canonical per-HTTPRoute per-rule route-match
13910/// axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
13911/// materializer's per-Aplicacao `HTTPRoute` fan-out, a future
13912/// per-edge `GRPCRoute` renderer whose per-rule request-match
13913/// predicate nests under the same axis convention, a future
13914/// per-route header-match / query-match renderer whose per-predicate
13915/// list binds against this same axis) inherits the same value by
13916/// construction with no opportunity for per-renderer drift.
13917///
13918/// Same "the typed constant lives in one place" discipline the
13919/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
13920/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
13921/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
13922/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
13923/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
13924/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
13925/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) lifts apply on the peer
13926/// canonical-Gateway-API-HTTPRoute-per-rule-body-axis surface.
13927///
13928/// [cm]: ../../caixa_mesh/index.html
13929pub const GATEWAY_API_KEY_MATCHES: &str = "matches";
13930
13931/// Canonical K8s Gateway API `Gateway` per-listener-set container-axis
13932/// key every `gateway_routes`-emitted `Gateway` document mounts its
13933/// per-Gateway `[{name, port, protocol, hostname}]` L7-listener fan-out
13934/// list under (`spec.listeners[]`). Pairs with the sibling
13935/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) +
13936/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) — the Gateway API v1 CRD
13937/// schema pins the per-Gateway L7-listener fan-out through the
13938/// `spec.listeners[]` container axis (each entry names one listener the
13939/// Gateway accepts external traffic on; the sibling
13940/// `spec.parentRefs[]` + `spec.rules[].backendRefs[]` container axes
13941/// carry the per-HTTPRoute parent-Gateway attachment + per-rule
13942/// backend-destination fan-out halves under the paired `HTTPRoute`
13943/// `spec` block), so drift on the per-Gateway L7-listener-set axis is
13944/// exactly as load-bearing as drift on the per-HTTPRoute parent-Gateway-
13945/// binding + per-rule backend-destination axes it accompanies (the K8s
13946/// apiserver-side Gateway API CRD schema validator drops any `spec`
13947/// block whose L7-listener-set container axis carries an unrecognized
13948/// key — a `"listener"` / `"listen"` / `"servers"` typo silently emits
13949/// a `Gateway` whose L7-listener fan-out the Gateway API
13950/// implementation's per-Gateway reconcile loop no-ops entirely: no
13951/// listener is opened, and every external `:entrada` flow the Gateway
13952/// was authored to accept drops at the gateway-class-controller's per-
13953/// Gateway HTTP-listener fan-in with no field naming the L7-listener-
13954/// set-axis-drift root cause).
13955///
13956/// The single source of truth the rendered Aplicacao Gateway-API-side
13957/// ingress bundle's per-Gateway L7-listener-set-axis-naming reaches
13958/// for:
13959///
13960///   - the rendered `Gateway` document's `spec.listeners[]` axis
13961///     (caixa-mesh/src/lib.rs — the `gateway_routes` per-Aplicacao
13962///     `Gateway`'s `g_spec.insert("listeners", …)` call).
13963///
13964/// The per-Gateway L7-listener-set container axis names the same
13965/// Gateway-API-implementation-side per-Gateway inbound-traffic-
13966/// acceptance-vector fan-out container as the sibling
13967/// [`GATEWAY_API_KEY_PARENT_REFS`] per-HTTPRoute parent-Gateway-binding
13968/// container axis + [`GATEWAY_API_KEY_BACKEND_REFS`] per-rule backend-
13969/// destination container axis it accompanies, and must move together
13970/// on any future Gateway API rebrand (an upstream SIG-Network Gateway
13971/// API v2 rename of the L7-listener-set axis from `listeners` to
13972/// `servers` / `endpoints` / `bindings`, coordinated with the Gateway
13973/// API deprecation cycle). Until this lift landed the axis carried an
13974/// inline `listeners` literal at the one production-code occurrence in
13975/// caixa-mesh/src/lib.rs (the `gateway_routes` per-Aplicacao Gateway's
13976/// `g_spec.insert("listeners", …)` call) plus a matching test-fixture
13977/// navigation inside the in-file `gateway_listener_carries_aplicacao_host`
13978/// pin's `.get("listeners")` traversal — two occurrences of the same
13979/// load-bearing Gateway-API-CRD-`listeners`-axis-key convention, drift-
13980/// prone by construction. A drift on the production site to
13981/// `"listener"` / `"listen"` / `"servers"` would have surfaced as a
13982/// Gateway API implementation-side schema validator drop at apply time
13983/// (the affected `Gateway`'s L7-listener-set axis the CRD schema
13984/// validator recognizes as unknown), with every external `:entrada`
13985/// flow the Gateway was authored to accept dropping at the gateway-
13986/// class-controller's per-Gateway reconcile with no field naming the
13987/// L7-listener-set-drift root cause. A drift on the test-fixture side
13988/// silently masks the emission-side pin (`.get("listeners")` returns
13989/// `None` under both the drifted-key emitter and the drifted-key probe
13990/// — the downstream `.and_then(|l| l.as_sequence())` /
13991/// `.and_then(|s| s.first())` chain short-circuits vacuously because
13992/// the outer per-Gateway L7-listener-set lookup is itself `None`).
13993///
13994/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
13995/// "every recurring shape becomes a generator before it becomes a
13996/// pattern; every pattern becomes a library before it becomes
13997/// duplicated code. The duplication budget is zero.") promotes the
13998/// constant to a typed substrate-side `&'static str` on the same
13999/// trajectory the [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14000/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14001/// [`CILIUM_KEY_PORTS`] (1087693) /
14002/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14003/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14004/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14005/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14006/// [`KUBE_KEY_RULES`] (a205eb3) lifts established on the sibling
14007/// canonical-Gateway-API-HTTPRoute-body-axis /
14008/// canonical-Cilium-CNP-body-axis surfaces — pivots the per-HTTPRoute-
14009/// body-axis lift discipline onto the sibling per-Gateway-body-axis
14010/// surface, extending the per-Gateway-API-CRD-body-axis canonical-
14011/// string-pin set (`parentRefs`, `backendRefs`, `listeners`, future
14012/// `hostnames`) the M3 Aplicacao mesh renderer's external `:entrada`
14013/// ingress contract rests on across the Gateway API CRD-side body-
14014/// shape. The render-side consumer now threads the same `&'static
14015/// str` through its `g_spec.insert(…)` call so a future Gateway API
14016/// rebrand on the L7-listener-set axis (or an upstream SIG-Network
14017/// Gateway API v2 rename to a per-CRD sibling name) lands in one
14018/// place; every future renderer that reaches for the canonical per-
14019/// Gateway L7-listener-set axis (the future M4
14020/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
14021/// `Gateway` fan-out, a future per-cluster `GatewayClass` /
14022/// `ReferenceGrant` renderer whose per-Gateway listener-set enumeration
14023/// binds against this same axis, a future per-listener TLS terminator
14024/// renderer whose per-listener `tls.mode: Terminate` overlay nests
14025/// under the same axis convention) inherits the same value by
14026/// construction with no opportunity for per-renderer drift.
14027///
14028/// Same "the typed constant lives in one place" discipline the
14029/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14030/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14031/// [`CILIUM_KEY_PORTS`] (1087693) /
14032/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14033/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14034/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14035/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14036/// [`KUBE_KEY_RULES`] (a205eb3) lifts apply on the peer canonical-
14037/// Gateway-API-Gateway-body-axis surface.
14038///
14039/// [cm]: ../../caixa_mesh/index.html
14040pub const GATEWAY_API_KEY_LISTENERS: &str = "listeners";
14041
14042/// Canonical K8s Gateway API `Gateway` per-listener DNS-host-discriminator
14043/// axis key every `gateway_routes`-emitted `Gateway` document mounts each
14044/// listener's virtual-host name under
14045/// (`spec.listeners[].hostname`). Pairs with the sibling
14046/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) — the Gateway API v1 CRD schema
14047/// pins the per-Gateway L7-listener-set fan-out through the
14048/// `spec.listeners[]` container axis (each entry names one listener the
14049/// Gateway accepts external traffic on) and pins each entry's per-listener
14050/// DNS-host discriminator under the nested `hostname` axis (Gateway API v1
14051/// `Listener.hostname` — `PreciseHostname` string, optional per-listener
14052/// virtual-host filter the Gateway-API-implementation-side per-Gateway
14053/// reconcile loop honors when routing external inbound traffic against
14054/// SNI at the TLS handshake / `Host:` header at the HTTP request line), so
14055/// drift on the per-listener DNS-host discriminator axis is exactly as
14056/// load-bearing as drift on the per-Gateway L7-listener-set container
14057/// axis it nests under (the K8s apiserver-side Gateway API CRD schema
14058/// validator drops any per-listener entry whose DNS-host discriminator
14059/// axis carries an unrecognized key — a `"host"` / `"vhost"` /
14060/// `"serverName"` typo silently emits a `Gateway` whose per-listener
14061/// virtual-host filter the Gateway API implementation's per-listener SNI /
14062/// `Host:` header dispatch loop no-ops entirely: the listener accepts
14063/// traffic on the wildcard host rather than the typed `:entrada :host`
14064/// the Aplicacao author declared, and every external `:entrada` flow the
14065/// listener was authored to accept lands on the wrong virtual-host filter
14066/// with no field naming the DNS-host-discriminator-axis-drift root
14067/// cause).
14068///
14069/// The single source of truth the rendered Aplicacao Gateway-API-side
14070/// ingress bundle's per-Gateway per-listener DNS-host-discriminator-axis-
14071/// naming reaches for:
14072///
14073///   - the rendered `Gateway` document's `spec.listeners[].hostname` axis
14074///     (caixa-mesh/src/lib.rs — the `gateway_routes` per-Aplicacao
14075///     `Gateway`'s per-listener `listener.insert("hostname", …)` call
14076///     seeded from the Aplicacao's `:entrada :host` slot).
14077///
14078/// The per-listener DNS-host discriminator axis names the same Gateway-
14079/// API-implementation-side per-listener virtual-host filter container as
14080/// the sibling [`GATEWAY_API_KEY_LISTENERS`] per-Gateway L7-listener-set
14081/// container axis it nests under, and must move together on any future
14082/// Gateway API rebrand (an upstream SIG-Network Gateway API v2 rename of
14083/// the per-listener DNS-host discriminator axis from `hostname` to `host`
14084/// / `vhost` / `serverName`, coordinated with the Gateway API deprecation
14085/// cycle). Until this lift landed the axis carried an inline `hostname`
14086/// literal at the one production-code occurrence in caixa-mesh/src/lib.rs
14087/// (the `gateway_routes` per-Aplicacao Gateway's per-listener
14088/// `listener.insert("hostname", …)` call) plus a matching test-fixture
14089/// navigation inside the in-file `gateway_listener_carries_aplicacao_host`
14090/// pin's `.get("hostname")` traversal — two occurrences of the same load-
14091/// bearing Gateway-API-CRD-`hostname`-axis-key convention, drift-prone by
14092/// construction. A drift on the production site to `"host"` / `"vhost"` /
14093/// `"serverName"` would have surfaced as a Gateway API implementation-
14094/// side schema validator drop at apply time (the affected listener's per-
14095/// listener DNS-host discriminator axis the CRD schema validator
14096/// recognizes as unknown), with every external `:entrada` flow landing on
14097/// the wildcard virtual-host filter rather than the typed `:entrada
14098/// :host` at the gateway-class-controller's per-listener dispatch with no
14099/// field naming the DNS-host-discriminator-drift root cause. A drift on
14100/// the test-fixture side silently masks the emission-side pin
14101/// (`.get("hostname")` returns `None` under both the drifted-key emitter
14102/// and the drifted-key probe — the downstream `.and_then(|h| h.as_str())`
14103/// chain short-circuits vacuously because the outer per-listener DNS-
14104/// host discriminator lookup is itself `None`).
14105///
14106/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
14107/// "every recurring shape becomes a generator before it becomes a
14108/// pattern; every pattern becomes a library before it becomes
14109/// duplicated code. The duplication budget is zero.") promotes the
14110/// constant to a typed substrate-side `&'static str` on the same
14111/// trajectory the [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14112/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14113/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14114/// [`CILIUM_KEY_PORTS`] (1087693) /
14115/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14116/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14117/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14118/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14119/// [`KUBE_KEY_RULES`] (a205eb3) lifts established on the sibling
14120/// canonical-Gateway-API-CRD-body-axis /
14121/// canonical-Cilium-CNP-body-axis surfaces — nests the per-Gateway-API-
14122/// CRD-body-axis lift discipline one level deeper onto the sibling per-
14123/// listener body-axis surface, extending the per-Gateway-API-CRD-body-
14124/// axis canonical-string-pin set (`parentRefs`, `backendRefs`,
14125/// `listeners`, `hostname`, future `hostnames`) the M3 Aplicacao mesh
14126/// renderer's external `:entrada` ingress contract rests on across the
14127/// Gateway API CRD-side body-shape. The render-side consumer now threads
14128/// the same `&'static str` through its per-listener `listener.insert(…)`
14129/// call so a future Gateway API rebrand on the per-listener DNS-host
14130/// discriminator axis (or an upstream SIG-Network Gateway API v2 rename
14131/// to a per-CRD sibling name) lands in one place; every future renderer
14132/// that reaches for the canonical per-listener DNS-host discriminator
14133/// axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
14134/// materializer's per-Aplicacao `Gateway` fan-out, a future per-listener
14135/// TLS terminator renderer whose per-listener `tls.certificateRefs[]`
14136/// resolution keys off the same per-listener virtual-host filter, a
14137/// future per-cluster wildcard-host `Gateway` renderer whose per-listener
14138/// SNI wildcard `*.example.com` matcher binds against this same axis)
14139/// inherits the same value by construction with no opportunity for per-
14140/// renderer drift.
14141///
14142/// Same "the typed constant lives in one place" discipline the
14143/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14144/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14145/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14146/// [`CILIUM_KEY_PORTS`] (1087693) /
14147/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14148/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14149/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14150/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14151/// [`KUBE_KEY_RULES`] (a205eb3) lifts apply on the peer canonical-
14152/// Gateway-API-Gateway-per-listener-body-axis surface.
14153///
14154/// [cm]: ../../caixa_mesh/index.html
14155pub const GATEWAY_API_KEY_HOSTNAME: &str = "hostname";
14156
14157/// Canonical K8s Gateway API `HTTPRoute` spec-level DNS-host-filter axis key
14158/// every `gateway_routes`-emitted `HTTPRoute` document mounts the route's
14159/// per-route virtual-host filter list under (`spec.hostnames[]`). The
14160/// plural sibling of [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) — same
14161/// Gateway-API-CRD DNS-host-discriminator convention nested one level up on
14162/// the sibling `HTTPRoute` per-route body-axis surface, distinct spelling
14163/// (`hostnames` — plural — is the `HTTPRoute` spec-level filter list; the
14164/// singular `hostname` axis it pairs against is the per-`Gateway`-listener
14165/// virtual-host discriminator).
14166///
14167/// The Gateway API v1 CRD schema pins the per-`HTTPRoute` DNS-host filter
14168/// through the spec-level `hostnames[]` container axis (a list of DNS
14169/// `PreciseHostname` strings, each one an additional virtual-host filter
14170/// the Gateway-API-implementation-side per-route reconcile loop honors
14171/// when routing external inbound traffic against SNI at the TLS handshake
14172/// / `Host:` header at the HTTP request line and against the sibling
14173/// [`GATEWAY_API_KEY_PARENT_REFS`]-declared parent Gateway's per-listener
14174/// [`GATEWAY_API_KEY_HOSTNAME`] filter set). Drift on the per-route DNS-
14175/// host filter axis is exactly as load-bearing as drift on the sibling
14176/// per-listener DNS-host discriminator axis (`hostname`): the K8s
14177/// apiserver-side Gateway API CRD schema validator drops any per-route
14178/// entry whose DNS-host-filter axis carries an unrecognized key — a
14179/// `"hosts"` / `"vhosts"` / `"serverNames"` typo silently emits an
14180/// `HTTPRoute` whose per-route virtual-host filter list the Gateway API
14181/// implementation's per-route SNI / `Host:` header dispatch loop no-ops
14182/// entirely: the route accepts traffic on every host the parent Gateway's
14183/// listener accepts rather than the typed `:entrada :host` the Aplicacao
14184/// author declared, and every external `:entrada` flow the route was
14185/// authored to accept lands on the wildcard virtual-host filter with no
14186/// field naming the DNS-host-filter-axis-drift root cause.
14187///
14188/// The single source of truth the rendered Aplicacao Gateway-API-side
14189/// ingress bundle's per-`HTTPRoute` spec-level DNS-host-filter-axis-naming
14190/// reaches for:
14191///
14192///   - the rendered `HTTPRoute` document's `spec.hostnames[]` axis
14193///     (caixa-mesh/src/lib.rs — the `gateway_routes` per-Aplicacao
14194///     `HTTPRoute`'s spec-level `r_spec.insert("hostnames", …)` call
14195///     seeded from the Aplicacao's `:entrada :host` slot as a
14196///     single-element sequence).
14197///
14198/// The per-route DNS-host filter axis names the same Gateway-API-
14199/// implementation-side per-route virtual-host filter list container as the
14200/// sibling [`GATEWAY_API_KEY_PARENT_REFS`] per-route parent-Gateway-
14201/// binding container axis it sits beside under `spec.*`, and must move
14202/// together on any future Gateway API rebrand (an upstream SIG-Network
14203/// Gateway API v2 rename of the per-route DNS-host filter axis from
14204/// `hostnames` to `hosts` / `vhosts` / `serverNames`, coordinated with
14205/// the Gateway API deprecation cycle). Until this lift landed the axis
14206/// carried an inline `hostnames` literal at the one production-code
14207/// occurrence in caixa-mesh/src/lib.rs (the `gateway_routes` per-
14208/// Aplicacao `HTTPRoute`'s spec-level `r_spec.insert("hostnames", …)`
14209/// call) — one occurrence today, but the sibling per-Gateway-API-CRD-
14210/// body-axis lifts ([`GATEWAY_API_KEY_LISTENERS`] / [`GATEWAY_API_KEY_HOSTNAME`]
14211/// / [`GATEWAY_API_KEY_PARENT_REFS`] / [`GATEWAY_API_KEY_BACKEND_REFS`])
14212/// each closed on the same one-production-emitter-plus-future-test-
14213/// fixture shape before a future per-route DNS-host-filter navigator
14214/// picked up the second occurrence, and the same lift-before-the-second-
14215/// site discipline applies here.
14216///
14217/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
14218/// "every recurring shape becomes a generator before it becomes a
14219/// pattern; every pattern becomes a library before it becomes
14220/// duplicated code. The duplication budget is zero.") promotes the
14221/// constant to a typed substrate-side `&'static str` on the same
14222/// trajectory the [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14223/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14224/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14225/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14226/// [`CILIUM_KEY_PORTS`] (1087693) /
14227/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14228/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14229/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14230/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14231/// [`KUBE_KEY_RULES`] (a205eb3) lifts established on the sibling
14232/// canonical-Gateway-API-CRD-body-axis /
14233/// canonical-Cilium-CNP-body-axis surfaces — closes the per-Gateway-API-
14234/// CRD `HTTPRoute` per-route body-axis lift pair across the singular /
14235/// plural DNS-host discriminator surface (`hostname` at the parent-
14236/// Gateway per-listener discriminator + `hostnames` at the child
14237/// HTTPRoute per-route filter list), so both halves of the DNS-host
14238/// discriminator convention across the `(Gateway, HTTPRoute)` pair the
14239/// M3 Aplicacao mesh renderer's external `:entrada` ingress contract
14240/// emits together now live as one lifted `&'static str` apiece. The
14241/// render-side consumer now threads the same `&'static str` through its
14242/// spec-level `r_spec.insert(…)` call so a future Gateway API rebrand on
14243/// the per-route DNS-host filter axis (or an upstream SIG-Network
14244/// Gateway API v2 rename to a per-CRD sibling name) lands in one place;
14245/// every future renderer that reaches for the canonical per-route DNS-
14246/// host filter axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
14247/// materializer's per-Aplicacao `HTTPRoute` fan-out, a future per-route
14248/// wildcard-host `*.example.com` filter emitter, a future per-Aplicacao
14249/// multi-`:entrada` `HTTPRoute` fan-out whose per-route DNS-host filter
14250/// lists partition inbound traffic across the same parent Gateway's
14251/// per-listener discriminator) inherits the same value by construction
14252/// with no opportunity for per-renderer drift.
14253///
14254/// Same "the typed constant lives in one place" discipline the
14255/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14256/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14257/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14258/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14259/// [`CILIUM_KEY_PORTS`] (1087693) /
14260/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14261/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14262/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14263/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14264/// [`KUBE_KEY_RULES`] (a205eb3) lifts apply on the peer canonical-
14265/// Gateway-API-HTTPRoute-per-route-body-axis surface.
14266///
14267/// [cm]: ../../caixa_mesh/index.html
14268pub const GATEWAY_API_KEY_HOSTNAMES: &str = "hostnames";
14269
14270/// Canonical K8s Gateway API `HTTPRoute` per-rule request-timeout-policy
14271/// body-axis key every `gateway_routes`-emitted `HTTPRoute` document mounts
14272/// its per-rule `:politicas :timeout` overlay under
14273/// (`spec.rules[].timeouts`). Sibling per-rule-body-axis peer to
14274/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) and
14275/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) — same Gateway-API-CRD-body-axis
14276/// discipline nested one level deeper onto the per-rule request-deadline
14277/// slot the Gateway API v1 CRD schema pins under `HTTPRoute.spec.rules[]`.
14278///
14279/// The Gateway API v1 CRD schema pins the per-rule request-timeout policy
14280/// through the `HTTPRouteTimeouts` sub-shape mounted at
14281/// `spec.rules[].timeouts`, whose `request` / `backendRequest` scalars
14282/// carry the per-rule deadline the Gateway-API-implementation-side per-
14283/// rule request-dispatch loop compares each accepted request's
14284/// wall-clock elapsed time against before cancelling the in-flight
14285/// backend call. Drift on the per-rule timeout-policy body-axis is
14286/// exactly as load-bearing as drift on the sibling per-rule backend-
14287/// destination axis (`backendRefs`): the K8s apiserver-side Gateway API
14288/// CRD schema validator drops any per-rule entry whose per-rule
14289/// timeout-policy axis carries an unrecognized key — a
14290/// `"timeout"` (singular) / `"timeoutPolicy"` / `"deadlines"` typo
14291/// silently emits an `HTTPRoute` whose per-rule timeout-policy the
14292/// Gateway API implementation's per-rule request-dispatch loop no-ops
14293/// entirely: the route accepts every inbound request with no per-rule
14294/// wall-clock deadline (the "no infinite blocking" guarantee
14295/// MESH-COMPOSITION.md §V mandates for every rendered per-`:politicas`
14296/// mesh-composition edge silently regresses to the pre-overlay
14297/// unbounded-request semantic, and every external `:entrada` flow the
14298/// route was authored to bound by the typed `:politicas :timeout` slot
14299/// runs to whatever backend deadline the resolved `ComputeUnit` /
14300/// `Service` / `ExternalName` backend's downstream infrastructure
14301/// (Envoy default listener idle timeout, node-local conntrack window,
14302/// TCP keepalive) picks — with no field naming the per-rule-timeout-
14303/// policy-axis-drift root cause).
14304///
14305/// The single source of truth the rendered Aplicacao Gateway-API-side
14306/// ingress bundle's per-`HTTPRoute` per-rule request-timeout-policy-
14307/// axis-naming reaches for:
14308///
14309///   - the rendered `HTTPRoute` document's per-rule `timeouts:` axis
14310///     (caixa-mesh/src/lib.rs — the `gateway_routes` per-Aplicacao
14311///     `HTTPRoute`'s per-rule `rule.insert("timeouts", …)` call
14312///     seeded from the Aplicacao's `:politicas :timeout` overlay
14313///     when the slot is set, elided from the emit sequence when the
14314///     slot is unset).
14315///
14316/// The per-rule request-timeout-policy axis names the same Gateway-
14317/// API-implementation-side per-rule request-dispatch deadline
14318/// container as the sibling [`GATEWAY_API_KEY_BACKEND_REFS`] per-rule
14319/// backend-destination container axis it sits beside under
14320/// `spec.rules[].*`, and must move together on any future Gateway API
14321/// rebrand (an upstream SIG-Network Gateway API v2 rename of the per-
14322/// rule timeout-policy axis from `timeouts` to `timeout` /
14323/// `timeoutPolicy` / `deadlines`, coordinated with the Gateway API
14324/// deprecation cycle). Until this lift landed the axis carried an
14325/// inline `timeouts` literal at nine physical sites in
14326/// caixa-mesh/src/lib.rs (one production emitter at the
14327/// `gateway_routes` per-rule `rule.insert(…)` call plus eight test-
14328/// side navigators pinning the overlay's presence, absence,
14329/// canonical-duration-format contract, per-rule fan-out under
14330/// multi-`:entrada :paths`, and independent-axis coexistence with the
14331/// sibling `retry` per-rule retry-policy axis), the highest per-axis
14332/// occurrence count of any un-lifted Gateway-API-CRD-body-axis in the
14333/// crate.
14334///
14335/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
14336/// "every recurring shape becomes a generator before it becomes a
14337/// pattern; every pattern becomes a library before it becomes
14338/// duplicated code. The duplication budget is zero.") promotes the
14339/// constant to a typed substrate-side `&'static str` on the same
14340/// trajectory the [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
14341/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14342/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14343/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14344/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14345/// [`CILIUM_KEY_PORTS`] (1087693) /
14346/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14347/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14348/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14349/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14350/// [`KUBE_KEY_RULES`] (a205eb3) lifts established on the sibling
14351/// canonical-Gateway-API-CRD-body-axis /
14352/// canonical-Cilium-CNP-body-axis surfaces — extends the per-Gateway-
14353/// API-`HTTPRoute` per-rule body-axis lift set onto the load-bearing
14354/// per-rule request-timeout-policy axis every downstream Gateway-API-
14355/// implementation-side per-rule request-dispatch loop keys off before
14356/// it can commit to a per-request wall-clock deadline. The render-
14357/// side consumer now threads the same `&'static str` through its
14358/// per-rule `rule.insert(…)` call and every test-side navigator's
14359/// `.get(…)` retrieval so a future Gateway API rebrand on the per-
14360/// rule timeout-policy axis (or an upstream SIG-Network Gateway API
14361/// v2 rename to a per-CRD sibling name) lands in one place; every
14362/// future renderer that reaches for the canonical per-rule timeout-
14363/// policy axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
14364/// materializer's per-Aplicacao per-rule timeout-policy fan-out, a
14365/// future per-edge `backendRequest` sub-timeout emitter honoring the
14366/// downstream `:politicas :backend-timeout` slot the M4 roadmap
14367/// acknowledges, a future per-cluster per-rule idle-timeout emitter
14368/// binding against this same axis) inherits the same value by
14369/// construction with no opportunity for per-renderer drift.
14370///
14371/// Same "the typed constant lives in one place" discipline the
14372/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
14373/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14374/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14375/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14376/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14377/// [`CILIUM_KEY_PORTS`] (1087693) /
14378/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14379/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14380/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14381/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14382/// [`KUBE_KEY_RULES`] (a205eb3) lifts apply on the peer canonical-
14383/// Gateway-API-HTTPRoute-per-rule-body-axis surface.
14384///
14385/// [cm]: ../../caixa_mesh/index.html
14386pub const GATEWAY_API_KEY_TIMEOUTS: &str = "timeouts";
14387
14388/// Canonical K8s Gateway API `HTTPRoute` per-rule retry-policy body-axis
14389/// key every `gateway_routes`-emitted `HTTPRoute` document mounts its
14390/// per-rule `:politicas :retries` overlay under (`spec.rules[].retry`).
14391/// Sibling per-rule-body-axis peer to [`GATEWAY_API_KEY_TIMEOUTS`]
14392/// (db31108) — same Gateway-API-CRD-body-axis discipline nested onto the
14393/// per-rule retry-budget slot the Gateway API v1 CRD schema pins under
14394/// `HTTPRoute.spec.rules[]` beside the sibling per-rule request-timeout-
14395/// policy container.
14396///
14397/// The Gateway API v1 CRD schema pins the per-rule retry policy through
14398/// the `HTTPRouteRetry` sub-shape mounted at `spec.rules[].retry`, whose
14399/// `attempts` scalar (peer to future `codes` retryable-status-code list
14400/// and `backoff` inter-attempt backoff-window scalars) carries the per-
14401/// rule retry-budget the Gateway-API-implementation-side per-rule
14402/// request-dispatch loop compares each failed attempt count against
14403/// before giving up on the in-flight backend call. Drift on the per-rule
14404/// retry-policy body-axis is exactly as load-bearing as drift on the
14405/// sibling per-rule request-timeout-policy axis (`timeouts`): the K8s
14406/// apiserver-side Gateway API CRD schema validator drops any per-rule
14407/// entry whose per-rule retry-policy axis carries an unrecognized key —
14408/// a `"retries"` (plural) / `"retryPolicy"` / `"budget"` typo silently
14409/// emits an `HTTPRoute` whose per-rule retry-budget the Gateway API
14410/// implementation's per-rule request-dispatch loop no-ops entirely: the
14411/// route accepts every inbound request with no per-rule retry budget
14412/// (the "no infinite retrying without bound" guarantee
14413/// MESH-COMPOSITION.md §V mandates for every rendered per-`:politicas`
14414/// mesh-composition edge silently regresses to the pre-overlay
14415/// unbounded-retry semantic, and every external `:entrada` flow the
14416/// route was authored to cap by the typed `:politicas :retries` slot
14417/// runs to whatever retry policy the resolved `ComputeUnit` /
14418/// `Service` / `ExternalName` backend's downstream infrastructure —
14419/// Envoy default retry policy, client SDK autoretry, node-local
14420/// conntrack retries — with no field naming the per-rule-retry-policy-
14421/// axis-drift root cause).
14422///
14423/// The single source of truth the rendered Aplicacao Gateway-API-side
14424/// ingress bundle's per-`HTTPRoute` per-rule retry-policy-axis-naming
14425/// reaches for:
14426///
14427///   - the rendered `HTTPRoute` document's per-rule `retry:` axis
14428///     (caixa-mesh/src/lib.rs — the `gateway_routes` per-Aplicacao
14429///     `HTTPRoute`'s per-rule `rule.insert("retry", …)` call seeded
14430///     from the Aplicacao's `:politicas :retries` overlay when the
14431///     slot is set, elided from the emit sequence when the slot is
14432///     unset).
14433///
14434/// The per-rule retry-policy axis names the same Gateway-API-
14435/// implementation-side per-rule request-dispatch retry-budget container
14436/// as the sibling [`GATEWAY_API_KEY_TIMEOUTS`] per-rule request-timeout-
14437/// policy container axis it sits beside under `spec.rules[].*`, and must
14438/// move together on any future Gateway API rebrand (an upstream
14439/// SIG-Network Gateway API v2 rename of the per-rule retry-policy axis
14440/// from `retry` to `retries` / `retryPolicy` / `budget`, coordinated
14441/// with the Gateway API deprecation cycle). Until this lift landed the
14442/// axis carried an inline `retry` literal at nine physical sites in
14443/// caixa-mesh/src/lib.rs (one production emitter at the `gateway_routes`
14444/// per-rule `rule.insert(…)` call plus eight test-side navigators
14445/// pinning the overlay's rule-level top-key-set, presence, absence,
14446/// per-rule fan-out under multi-`:entrada :paths`, round-trip of the
14447/// typed `u32` attempt count, YAML integer scalar-kind, and independent-
14448/// axis coexistence with the sibling `timeouts` per-rule request-
14449/// timeout-policy axis in both directions), the highest per-axis
14450/// occurrence count of any un-lifted Gateway-API-CRD-body-axis in the
14451/// crate — same nine-site count the peer sibling
14452/// [`GATEWAY_API_KEY_TIMEOUTS`] lift closed on the coexisting per-rule
14453/// request-timeout-policy axis.
14454///
14455/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
14456/// "every recurring shape becomes a generator before it becomes a
14457/// pattern; every pattern becomes a library before it becomes
14458/// duplicated code. The duplication budget is zero.") promotes the
14459/// constant to a typed substrate-side `&'static str` on the same
14460/// trajectory the [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
14461/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
14462/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14463/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14464/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14465/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14466/// [`CILIUM_KEY_PORTS`] (1087693) /
14467/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14468/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14469/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14470/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14471/// [`KUBE_KEY_RULES`] (a205eb3) lifts established on the sibling
14472/// canonical-Gateway-API-CRD-body-axis /
14473/// canonical-Cilium-CNP-body-axis surfaces — closes the pair of per-
14474/// Gateway-API-`HTTPRoute`-per-rule `:politicas` overlay axes
14475/// (`timeouts` for `:politicas :timeout`, `retry` for `:politicas
14476/// :retries`) both MESH-COMPOSITION.md §V "no infinite blocking / no
14477/// infinite retrying" guarantees rest on. The render-side consumer now
14478/// threads the same `&'static str` through its per-rule
14479/// `rule.insert(…)` call and every test-side navigator's `.get(…)`
14480/// retrieval so a future Gateway API rebrand on the per-rule retry-
14481/// policy axis lands in one place; every future renderer that reaches
14482/// for the canonical per-rule retry-policy axis (the future M4
14483/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
14484/// per-rule retry-policy fan-out, a future per-edge `codes`
14485/// retryable-status-code emitter honoring an M4-roadmap `:politicas
14486/// :retry-codes` slot, a future per-edge `backoff` inter-attempt
14487/// backoff-window emitter honoring an M4-roadmap `:politicas
14488/// :retry-backoff` slot) inherits the same value by construction with
14489/// no opportunity for per-renderer drift.
14490///
14491/// Same "the typed constant lives in one place" discipline the
14492/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
14493/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
14494/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14495/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14496/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14497/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
14498/// [`CILIUM_KEY_PORTS`] (1087693) /
14499/// [`CILIUM_KEY_FROM_ENDPOINTS`] (ecfa557) /
14500/// [`CILIUM_KEY_INGRESS`] (0400a9b) /
14501/// [`CILIUM_KEY_ENDPOINT_SELECTOR`] (7088789) /
14502/// [`CILIUM_KEY_TO_PORTS`] (c8d9cbf) /
14503/// [`KUBE_KEY_RULES`] (a205eb3) lifts apply on the peer canonical-
14504/// Gateway-API-HTTPRoute-per-rule-body-axis surface.
14505///
14506/// [cm]: ../../caixa_mesh/index.html
14507pub const GATEWAY_API_KEY_RETRY: &str = "retry";
14508
14509/// Canonical K8s Gateway API `HTTPRoute` per-rule retry-policy `attempts`
14510/// leaf scalar-key every `gateway_routes`-emitted `HTTPRoute` document
14511/// mounts its per-rule `:politicas :retries` typed `u32` attempt count
14512/// under (`spec.rules[].retry.attempts`). Leaf peer to the container-axis
14513/// parent [`GATEWAY_API_KEY_RETRY`] (231bbf5) — the sibling per-rule
14514/// retry-policy body-axis lifted in the immediately-preceding commit;
14515/// this closes the parent-leaf axis pair (`retry` container +
14516/// `attempts` leaf) the Gateway API v1 `HTTPRouteRetry` sub-shape pins
14517/// under `HTTPRoute.spec.rules[].retry.attempts`.
14518///
14519/// The Gateway API v1 CRD schema pins the per-rule retry attempt budget
14520/// through the `HTTPRouteRetry.attempts` scalar (peer to future
14521/// `HTTPRouteRetry.codes` retryable-status-code list and
14522/// `HTTPRouteRetry.backoff` inter-attempt backoff-window scalars) the
14523/// Gateway-API-implementation-side per-rule request-dispatch loop
14524/// compares each failed backend attempt count against before giving up
14525/// on the in-flight backend call. Drift on this leaf key is exactly as
14526/// load-bearing as drift on the parent per-rule retry-policy container
14527/// axis (`retry`): the K8s apiserver-side Gateway API CRD schema
14528/// validator drops any per-rule `retry:` entry whose leaf attempt-count
14529/// key carries an unrecognized name — a `"attempt"` (singular) /
14530/// `"count"` / `"tries"` / `"maxAttempts"` typo silently emits an
14531/// `HTTPRoute` whose per-rule retry-budget the Gateway-API-
14532/// implementation-side per-rule request-dispatch loop no-ops entirely
14533/// (the sub-shape is parsed as an empty `HTTPRouteRetry` with the
14534/// typed `u32` attempt count silently discarded, the route accepts
14535/// every inbound request with no per-rule retry budget — the "no
14536/// infinite retrying without bound" guarantee MESH-COMPOSITION.md §V
14537/// mandates for every rendered per-`:politicas` mesh-composition edge
14538/// silently regresses to the pre-overlay unbounded-retry semantic,
14539/// and every external `:entrada` flow the route was authored to cap
14540/// by the typed `:politicas :retries` slot runs to whatever retry
14541/// policy the resolved backend's downstream infrastructure — Envoy
14542/// default retry policy, client SDK autoretry, node-local conntrack
14543/// retries — picks with no field naming the per-rule-retry-attempts-
14544/// leaf-key drift root cause).
14545///
14546/// The single source of truth the rendered Aplicacao Gateway-API-side
14547/// ingress bundle's per-`HTTPRoute` per-rule retry-attempts-leaf-key-
14548/// naming reaches for:
14549///
14550///   - the rendered `HTTPRoute` document's per-rule
14551///     `retry.attempts:` leaf (caixa-mesh/src/lib.rs — the
14552///     `gateway_routes` per-Aplicacao `HTTPRoute`'s per-rule
14553///     `single_field_overlay(spec.politicas.retries, …)` call seeded
14554///     from the Aplicacao's `:politicas :retries` overlay when the
14555///     slot is set, emitting the typed `u32` attempt count under this
14556///     leaf key inside the sibling [`GATEWAY_API_KEY_RETRY`] container
14557///     axis).
14558///
14559/// The per-rule retry-attempts leaf key names the same Gateway-API-
14560/// implementation-side per-rule request-dispatch retry-budget scalar
14561/// as the sibling parent [`GATEWAY_API_KEY_RETRY`] container axis it
14562/// sits nested inside under `spec.rules[].retry.attempts`, and must
14563/// move together with the parent on any future Gateway API rebrand
14564/// (an upstream SIG-Network Gateway API v2 rename of the per-rule
14565/// retry-attempts leaf key from `attempts` to `attempt` / `count` /
14566/// `tries` / `maxAttempts`, coordinated with the Gateway API
14567/// deprecation cycle). Until this lift landed the leaf key carried
14568/// an inline `attempts` literal at six physical code sites in
14569/// caixa-mesh/src/lib.rs (one production emitter at the `gateway_routes`
14570/// per-rule `single_field_overlay(spec.politicas.retries, "attempts", …)`
14571/// call plus five test-side navigators pinning the overlay's leaf-
14572/// count value, round-trip of the typed `u32` attempt count, YAML
14573/// integer scalar-kind, per-rule fan-out under multi-`:entrada
14574/// :paths`, and independent-axis coexistence with the sibling
14575/// `timeouts` per-rule request-timeout-policy axis).
14576///
14577/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
14578/// "every recurring shape becomes a generator before it becomes a
14579/// pattern; every pattern becomes a library before it becomes
14580/// duplicated code. The duplication budget is zero.") promotes the
14581/// constant to a typed substrate-side `&'static str` on the same
14582/// trajectory the [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
14583/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
14584/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
14585/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14586/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14587/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14588/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) lifts established on
14589/// the sibling canonical-Gateway-API-CRD-body-axis surface — closes
14590/// the parent-leaf axis pair (`retry` container +
14591/// `attempts` leaf) the K8s Gateway API v1 `HTTPRouteRetry` sub-shape
14592/// pins under `HTTPRoute.spec.rules[].retry.attempts`, both
14593/// MESH-COMPOSITION.md §V "no infinite retrying" guarantees rest on.
14594/// The render-side consumer now threads the same `&'static str`
14595/// through its `single_field_overlay` call and every test-side
14596/// navigator's `.get(…)` retrieval so a future Gateway API rebrand
14597/// on the per-rule retry-attempts leaf lands in one place; every
14598/// future renderer that reaches for the canonical per-rule retry-
14599/// attempts leaf (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao`
14600/// CR materializer's per-Aplicacao per-rule retry-attempts fan-out)
14601/// inherits the same value by construction with no opportunity for
14602/// per-renderer drift.
14603///
14604/// Same "the typed constant lives in one place" discipline the
14605/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
14606/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) lifts apply on the peer
14607/// canonical-Gateway-API-HTTPRoute-per-rule-body-axis surface, now
14608/// extended one nesting level deeper onto the retry-container-leaf
14609/// scalar.
14610///
14611/// [cm]: ../../caixa_mesh/index.html
14612pub const GATEWAY_API_KEY_ATTEMPTS: &str = "attempts";
14613
14614/// Canonical K8s Gateway API `HTTPRoute` per-rule request-timeout-policy
14615/// `request` leaf scalar-key every `gateway_routes`-emitted `HTTPRoute`
14616/// document mounts its per-rule `:politicas :timeout` typed K8s-duration
14617/// string under (`spec.rules[].timeouts.request`). Leaf peer to the
14618/// container-axis parent [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) — the
14619/// sibling per-rule request-timeout-policy body-axis — and to the peer
14620/// retry-container leaf [`GATEWAY_API_KEY_ATTEMPTS`] (e2e136b) landed
14621/// on the parallel `retry.attempts` nesting; this closes the parent-leaf
14622/// axis pair (`timeouts` container + `request` leaf) the K8s Gateway API
14623/// v1 `HTTPRouteTimeouts` sub-shape pins under
14624/// `HTTPRoute.spec.rules[].timeouts.request`.
14625///
14626/// The Gateway API v1 CRD schema pins the per-rule request-deadline
14627/// through the `HTTPRouteTimeouts.request` scalar (peer to
14628/// `HTTPRouteTimeouts.backendRequest` per-attempt backend-call deadline
14629/// scalar) the Gateway-API-implementation-side per-rule request-dispatch
14630/// loop keys off before it commits to a per-request wall-clock deadline.
14631/// Drift on this leaf key is exactly as load-bearing as drift on the
14632/// parent per-rule request-timeout-policy container axis (`timeouts`):
14633/// the K8s apiserver-side Gateway API CRD schema validator drops any
14634/// per-rule `timeouts:` entry whose leaf request-deadline key carries an
14635/// unrecognized name — a `"deadline"` / `"requestTimeout"` /
14636/// `"timeout"` / `"upstreamRequest"` typo silently emits an `HTTPRoute`
14637/// whose per-rule request-deadline the Gateway-API-implementation-side
14638/// per-rule request-dispatch loop no-ops entirely (the sub-shape is
14639/// parsed as an empty `HTTPRouteTimeouts` with the typed duration
14640/// silently discarded, the route accepts every inbound request with no
14641/// per-rule request wall-clock deadline — the "no infinite blocking"
14642/// guarantee MESH-COMPOSITION.md §V mandates for every rendered
14643/// per-`:politicas` mesh-composition edge silently regresses to the
14644/// pre-overlay unbounded-blocking semantic, and every external
14645/// `:entrada` flow the route was authored to cap by the typed
14646/// `:politicas :timeout` slot runs to whatever request-deadline the
14647/// resolved backend's downstream infrastructure — Envoy default
14648/// route-timeout, client SDK deadline, node-local conntrack idle-close
14649/// — picks with no field naming the per-rule-request-timeout-leaf-key
14650/// drift root cause).
14651///
14652/// The single source of truth the rendered Aplicacao Gateway-API-side
14653/// ingress bundle's per-`HTTPRoute` per-rule request-deadline-leaf-key-
14654/// naming reaches for:
14655///
14656///   - the rendered `HTTPRoute` document's per-rule
14657///     `timeouts.request:` leaf (caixa-mesh/src/lib.rs — the
14658///     `gateway_routes` per-Aplicacao `HTTPRoute`'s per-rule
14659///     `single_field_overlay(spec.politicas.timeout, …)` call seeded
14660///     from the Aplicacao's `:politicas :timeout` overlay when the slot
14661///     is set, emitting the typed K8s-duration string under this leaf
14662///     key inside the sibling [`GATEWAY_API_KEY_TIMEOUTS`] container
14663///     axis).
14664///
14665/// The per-rule request-deadline leaf key names the same
14666/// Gateway-API-implementation-side per-rule request-dispatch wall-clock
14667/// deadline scalar as the sibling parent [`GATEWAY_API_KEY_TIMEOUTS`]
14668/// container axis it sits nested inside under
14669/// `spec.rules[].timeouts.request`, and must move together with the
14670/// parent on any future Gateway API rebrand (an upstream SIG-Network
14671/// Gateway API v2 rename of the per-rule request-deadline leaf key from
14672/// `request` to `deadline` / `requestTimeout` / `timeout` /
14673/// `upstreamRequest`, coordinated with the Gateway API deprecation
14674/// cycle). Until this lift landed the leaf key carried an inline
14675/// `request` literal at six physical code sites in
14676/// caixa-mesh/src/lib.rs (one production emitter at the
14677/// `gateway_routes` per-rule
14678/// `single_field_overlay(spec.politicas.timeout, "request", …)` call
14679/// plus five test-side navigators pinning the overlay's leaf-value
14680/// presence, the canonical `duration_codec::render` round-trip of a
14681/// 30s / 90s / 1m typed duration, per-rule fan-out under
14682/// multi-`:entrada :paths`, and independent-axis coexistence with the
14683/// sibling `retry` per-rule retry-policy axis).
14684///
14685/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
14686/// "every recurring shape becomes a generator before it becomes a
14687/// pattern; every pattern becomes a library before it becomes
14688/// duplicated code. The duplication budget is zero.") promotes the
14689/// constant to a typed substrate-side `&'static str` on the same
14690/// trajectory the [`GATEWAY_API_KEY_ATTEMPTS`] (e2e136b) /
14691/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
14692/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
14693/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
14694/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
14695/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
14696/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
14697/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) lifts established on the
14698/// sibling canonical-Gateway-API-CRD-body-axis surface — closes the
14699/// second parent-leaf axis pair (`timeouts` container + `request` leaf)
14700/// the K8s Gateway API v1 `HTTPRouteTimeouts` sub-shape pins under
14701/// `HTTPRoute.spec.rules[].timeouts.request`, sibling to the parent-
14702/// leaf pair (`retry` container + `attempts` leaf) closed in the
14703/// immediately-preceding [`GATEWAY_API_KEY_ATTEMPTS`] lift. Both
14704/// MESH-COMPOSITION.md §V "no infinite blocking / no infinite retrying"
14705/// guarantees now rest on typed lifts at both container-axis and leaf-
14706/// scalar-axis nesting levels of the two per-`:politicas` overlays.
14707/// The render-side consumer now threads the same `&'static str`
14708/// through its `single_field_overlay` call and every test-side
14709/// navigator's `.get(…)` retrieval so a future Gateway API rebrand on
14710/// the per-rule request-deadline leaf lands in one place; every future
14711/// renderer that reaches for the canonical per-rule request-deadline
14712/// leaf (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
14713/// materializer's per-Aplicacao per-rule request-deadline fan-out, a
14714/// future per-edge `backendRequest` per-attempt backend-call deadline
14715/// emitter) inherits the same value by construction with no opportunity
14716/// for per-renderer drift.
14717///
14718/// Same "the typed constant lives in one place" discipline the
14719/// [`GATEWAY_API_KEY_ATTEMPTS`] (e2e136b) /
14720/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
14721/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) lifts apply on the peer
14722/// canonical-Gateway-API-HTTPRoute-per-rule-body-axis surface, now
14723/// extended to the second per-rule container-leaf scalar (parallel to
14724/// the sibling `retry.attempts` container-leaf pair).
14725///
14726/// [cm]: ../../caixa_mesh/index.html
14727pub const GATEWAY_API_KEY_REQUEST: &str = "request";
14728
14729/// Canonical Helm library-chart name every `lareira-<nome>` chart depends
14730/// on — the `pleme-computeunit` library chart in
14731/// `pleme-io/helmworks/charts/pleme-computeunit` that owns the K8s
14732/// resource templates (ComputeUnit + Service + ScaledObject + ConfigMap)
14733/// every per-Servico chart consumes via Helm's per-dep alias convention
14734/// (when no `alias:` is set on a dependency, values are scoped under the
14735/// dependency's `name:`).
14736///
14737/// The single source of truth all three downstream library-name consumers
14738/// reach for:
14739///
14740///   - [`caixa-helm`][ch]'s `DEFAULT_LIBRARY_NAME` re-export — the
14741///     default value of `RenderOpts::library_name`, which drives both
14742///     the Chart.yaml `dependencies[0].name` axis
14743///     (`build_chart_yaml`) and the values.yaml wrap key
14744///     (`build_values_yaml`) so the rendered `lareira-<nome>` chart's
14745///     dep declaration and its values block agree by construction
14746///     (the 17ebd1a `opts.library_name` lift).
14747///   - [`caixa-flux`][cf]'s `DEFAULT_LIBRARY_NAME` re-export — the
14748///     wrap key the `cluster_bundle` `helmrelease.yaml` template uses
14749///     under `spec.values.<library>:` to thread the per-cluster
14750///     overrides (`enabled: true`) through to the rendered chart's
14751///     dep block. Helm's per-dep alias convention scopes those values
14752///     under the dependency's `name:`, so this wrap key must match the
14753///     chart's `dependencies[0].name` exactly — drift here silently
14754///     routes the values block nowhere at `helm template` /
14755///     `helm install` time, and the cluster comes up with the library
14756///     chart's defaults rather than the typed per-cluster overrides.
14757///   - Every future per-Servico renderer the absorption-roadmap
14758///     acknowledges (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
14759///     materializer's per-edge library-chart resolver, the future
14760///     per-cluster image-registry mirror's `<registry>-computeunit`
14761///     fork, the future per-edition library-chart variant the
14762///     substrate forks once `pleme-computeunit` outlives its scoping
14763///     intent).
14764///
14765/// Until this lift landed the canonical library-chart name lived as
14766/// two production-code call sites: a `pub const DEFAULT_LIBRARY_NAME:
14767/// &str = "pleme-computeunit"` in `caixa-helm` (the
14768/// `RenderOpts::library_name` default, consumed by both the chart's dep
14769/// name axis and the values.yaml wrap key axis) and an inline literal
14770/// `pleme-computeunit:` in `caixa-flux`'s `cluster_bundle`
14771/// `helmrelease.yaml` format-string template (the wrap key the per-
14772/// cluster `enabled: true` override is scoped under). Both consumers
14773/// reach for the same load-bearing Helm library-chart name, but no
14774/// shared constant linked them — the canonical
14775/// "duplicated `pub const` / inline literal across two renderers"
14776/// drift footgun the [`DEFAULT_NAMESPACE`] (a085b26) and
14777/// [`DEFAULT_SERVICO_PORT`] (1e22add) lifts close on the peer
14778/// canonical-K8s-axis-constant surface.
14779///
14780/// A future library-chart rebrand — the substrate forking
14781/// `pleme-computeunit` to `<registry>-computeunit` for a per-cluster
14782/// image-registry mirror, or to `aplicacao-computeunit` for the M4
14783/// typed-Aplicacao renderer's sibling library chart, or to any
14784/// per-edition variant the absorption-roadmap names — without a
14785/// coordinated edit on both consumers would have silently emitted a
14786/// per-Servico chart whose dep declared the new library name (because
14787/// the chart-side override flowed through `opts.library_name`) but
14788/// whose flux-side `HelmRelease.values.pleme-computeunit:` wrap key
14789/// still scoped under the old literal. Helm's per-dep values router
14790/// would route the per-cluster `enabled: true` override to *nowhere*
14791/// at `helm template` / `helm install` time, and the cluster's apply
14792/// would come up with the library chart's defaults — `enabled: false`,
14793/// the typed values block from the chart's own `values.yaml` rather
14794/// than the flux-side override — silently no-op'ing every per-cluster
14795/// override the operator set, far from the rebrand commit's source.
14796/// The apply-time symptom (the workload comes up with the library
14797/// chart's defaults instead of the per-cluster overrides) is invisible
14798/// at admission and surfaces only as "the service is up but not doing
14799/// what we configured it to do", typically far from the rebrand commit.
14800///
14801/// Lifting it to caixa-core's render-constants block alongside the
14802/// peer [`DEFAULT_NAMESPACE`] / [`DEFAULT_SERVICO_PORT`] makes the
14803/// library-name axis discipline structural: every renderer that
14804/// reaches for the canonical library-chart name consults the same
14805/// `&'static str`, and every future renderer inherits the same value
14806/// by construction with no opportunity for per-renderer drift. Same
14807/// "the typed constant lives in one place" discipline the
14808/// [`PLEME_LABEL_PREFIX`] (a8d4d57) / [`KUBE_KEY_API_VERSION`] /
14809/// [`LAREIRA_CHART_NAME_PREFIX`] lifts apply on the peer
14810/// shared-string axes.
14811///
14812/// [ch]: ../../caixa_helm/index.html
14813/// [cf]: ../../caixa_flux/index.html
14814pub const DEFAULT_LIBRARY_NAME: &str = "pleme-computeunit";
14815
14816/// Canonical Flux v2 `spec.interval` reconcile-poll cadence duration
14817/// scalar every [`caixa-flux`][cf]-emitted Flux v2 CR (the per-caixa
14818/// `cluster_bundle` triplet's `GitRepository` + `HelmRelease` +
14819/// `Kustomization`) declares as its default reconcile-schedule when the
14820/// per-caixa [`ClusterBundleOpts::for_caixa`][fc] seed doesn't carry an
14821/// operator-pinned override. Every rendered per-caixa Flux v2 CR consults
14822/// the same `&'static str` at seed time so a future substrate-side
14823/// reconcile-cadence migration (`"10m"` → `"5m"` once the Flux v2 source-
14824/// controller / helm-controller / kustomize-controller trio ships lower-
14825/// latency-poll optimizations that make per-CR cluster load safe at a
14826/// faster cadence, `"10m"` → `"15m"` on cost-optimized clusters where the
14827/// per-CR source-controller poll cost outweighs the reconcile-freshness
14828/// gain) is a one-line edit on this canonical declaration, not a
14829/// coordinated rewrite across the [`ClusterBundleOpts`] default seed and
14830/// every future per-target renderer the substrate adds.
14831///
14832/// The single source of truth the rendered per-caixa Flux v2 cluster
14833/// bundle's per-CR reconcile-poll cadence default seed reaches for:
14834///
14835///   - [`ClusterBundleOpts::for_caixa`][fc]'s per-caixa default seed
14836///     (caixa-flux/src/lib.rs — the `interval: <DEFAULT>.into()` field of
14837///     the [`ClusterBundleOpts`] struct default the substrate's per-caixa
14838///     `cluster_bundle` renderer threads through every emitted Flux v2 CR's
14839///     [`FLUX_KEY_INTERVAL`] axis verbatim).
14840///
14841/// The value is a valid Flux v2 reconcile-poll cadence duration scalar (per
14842/// the upstream Flux v2 `metav1.Duration` OpenAPI schema on each of the
14843/// three Flux v2 CRDs — `source.toolkit.fluxcd.io/v1/GitRepository.spec.
14844/// interval`, `helm.toolkit.fluxcd.io/v2/HelmRelease.spec.interval`,
14845/// `kustomize.toolkit.fluxcd.io/v1/Kustomization.spec.interval`): a
14846/// non-empty Go-duration-format string (e.g. `"10m"`, `"5m"`, `"1h30m"`),
14847/// which the Flux v2 controller-side per-CR admission gate parses via
14848/// `metav1.ParseDuration` before installing the per-CR watch. A future
14849/// rebrand on this lift cannot silently land a value the Flux v2
14850/// controller-side admission gate rejects at the *first* per-caixa
14851/// `HelmRelease` apply against a cluster, far from the rebrand commit's
14852/// source — the pin at the canonical lift documents the Go-duration-format
14853/// grammar contract with the Flux v2 admission gate every downstream
14854/// consumer of the rendered per-CR reconcile-cadence axis rests on.
14855///
14856/// Pairs with the sibling [`FLUX_KEY_INTERVAL`] (48db6e2) per-Flux-v2-CR
14857/// reconcile-poll cadence scalar-axis key the value the substrate seeds
14858/// here nests directly under across every rendered per-caixa Flux v2 CR
14859/// — the key half of the per-CR `spec.interval` scalar-key/scalar-value
14860/// pair lives at [`FLUX_KEY_INTERVAL`], the value half's substrate-side
14861/// default seed lives here. Same "the typed constant lives in one place"
14862/// discipline the [`DEFAULT_NAMESPACE`] (a085b26) /
14863/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) / [`DEFAULT_LIBRARY_NAME`]
14864/// (41438dc) / [`DEFAULT_SERVICO_PORT`] (1e22add) /
14865/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) /
14866/// [`DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) lifts apply on the peer
14867/// canonical-substrate-default-load-bearing-scalar surface — extends the
14868/// canonical-substrate-default single-sourcing discipline from the peer
14869/// substrate-side default-namespace / default-library-chart-name /
14870/// default-Servico-listen-port / default-Gateway-API-controller-name /
14871/// default-git-publish-tag-prefix surfaces onto the sibling default-Flux-
14872/// v2-per-CR-reconcile-poll-cadence surface every rendered per-caixa
14873/// Flux v2 cluster bundle CR carries.
14874///
14875/// [cf]: ../../caixa_flux/index.html
14876/// [fc]: ../../caixa_flux/struct.ClusterBundleOpts.html#method.for_caixa
14877pub const DEFAULT_FLUX_RECONCILE_INTERVAL: &str = "10m";
14878
14879/// Canonical Flux v2 `HelmRelease.spec.chart.spec.chart` per-CR chart-
14880/// directory-in-GitRepository-source sub-path scalar every
14881/// [`caixa-flux`][cf]-emitted `helmrelease.yaml` document declares as the
14882/// default chart-directory-in-git-source pointer when the per-caixa
14883/// [`ClusterBundleOpts::for_caixa`][fc] seed doesn't carry an operator-
14884/// pinned override. The Flux v2 source-controller resolves the pointer
14885/// relative to the paired [`FLUX_KIND_GIT_REPOSITORY`] the sibling
14886/// [`FLUX_KEY_SOURCE_REF`]-keyed `sourceRef:` block names — the substrate's
14887/// canonical contract with every caixa Servico's git repository is that
14888/// the per-caixa `lareira-<nome>` chart the peer `caixa-helm` renderer
14889/// emits lives at the `./chart/` sub-tree of the repository root, so the
14890/// helm-controller's per-CR chart-open loop keys off this exact scalar to
14891/// locate the [`HELM_CHART_YAML_FILENAME`] + [`HELM_VALUES_YAML_FILENAME`]
14892/// pair the per-caixa rendered chart declares. Every rendered per-caixa
14893/// `HelmRelease` CR consults the same `&'static str` at seed time so a
14894/// future substrate-side chart-directory-in-git-source rebrand
14895/// (`"chart"` → `"charts"` once a per-caixa multi-chart layout lands and
14896/// the substrate publishes N sibling `lareira-<nome>/` charts under one
14897/// git repository, `"chart"` → `"helm"` on a cross-language convention
14898/// alignment with sibling wasm-runtime substrates, `"chart"` → `"deploy"`
14899/// on a per-caixa-deploy-directory naming migration) is a one-line edit
14900/// on this canonical declaration, not a coordinated rewrite across the
14901/// [`ClusterBundleOpts`] default seed and every future per-target
14902/// renderer the substrate adds.
14903///
14904/// The single source of truth the rendered per-caixa Flux v2 cluster
14905/// bundle's per-CR chart-directory-in-git-source default seed reaches for:
14906///
14907///   - [`ClusterBundleOpts::for_caixa`][fc]'s per-caixa default seed
14908///     (caixa-flux/src/lib.rs — the `chart_path: <DEFAULT>.into()` field
14909///     of the [`ClusterBundleOpts`] struct default the substrate's per-
14910///     caixa `cluster_bundle` renderer threads through every emitted per-
14911///     caixa `helmrelease.yaml` document's [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`]
14912///     -keyed `spec.chart.spec.chart` axis verbatim).
14913///
14914/// The value is a valid Flux v2 `HelmRelease.spec.chart.spec.chart` scalar
14915/// (per the upstream Flux v2 `helm.toolkit.fluxcd.io/v2/HelmRelease` `OpenAPI`
14916/// schema — a non-empty string interpreted by the source-controller as a
14917/// relative directory-tree path from the paired `GitRepository` clone
14918/// root): a non-empty ASCII scalar with no leading path separator (which
14919/// would break the source-controller's relative-path composition against
14920/// the per-clone-root anchor). A future rebrand on this lift cannot
14921/// silently land an empty scalar or a leading-separator scalar the source-
14922/// controller-side per-CR chart-open loop would then reject at the *first*
14923/// per-caixa `HelmRelease` apply against a cluster, far from the rebrand
14924/// commit's source — the [`default_flux_chart_source_subpath_is_a_valid_relative_directory_scalar`]
14925/// pin trips at caixa-core build time on any drift past the typed floor.
14926///
14927/// Pairs with the sibling [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`] (0fef82e)
14928/// per-Flux-v2-`HelmRelease.spec.chart.spec.chart` leaf-scalar-key the
14929/// value the substrate seeds here nests directly under across every
14930/// rendered per-caixa `HelmRelease` CR — the key half of the per-CR
14931/// `spec.chart.spec.chart` scalar-key/scalar-value pair lives at
14932/// [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`], the value half's substrate-side
14933/// default seed lives here. Peer with [`flux_kustomization_source_subtree`]
14934/// on the sibling `Kustomization.spec.path` per-cluster / per-caixa `GitOps`-
14935/// repository-relative directory-tree seed composer — both name a load-
14936/// bearing directory-tree relative path the Flux v2 controller family's
14937/// per-CR reconcile loop navigates into, at the two paired axes of the
14938/// per-caixa `cluster_bundle` triplet (the `HelmRelease` chart-directory
14939/// axis names *where in the caixa's own git repo the chart lives*, the
14940/// `Kustomization` sub-tree axis names *where in the k8s-GitOps repo the
14941/// per-cluster manifest sub-tree lives*, and the two together close the
14942/// Flux v2 kustomize-controller → helm-controller reconcile-chain axis
14943/// the substrate's per-caixa cluster-bundle-triplet reconcile-topology
14944/// rests on).
14945///
14946/// Same "the typed constant lives in one place" discipline the
14947/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
14948/// (7197d38) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
14949/// [`DEFAULT_SERVICO_PORT`] (1e22add) / [`DEFAULT_GATEWAY_CLASS_NAME`]
14950/// (d9b0743) / [`DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
14951/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f) /
14952/// [`DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] (64bdb2b) /
14953/// [`DEFAULT_PLEME_GIT_ORG`] (9952bd9) lifts apply on the peer
14954/// canonical-substrate-default-load-bearing-scalar surface — extends the
14955/// canonical-substrate-default single-sourcing discipline from the peer
14956/// substrate-side default-namespace / default-library-chart-name /
14957/// default-Servico-listen-port / default-Gateway-API-controller-name /
14958/// default-git-publish-tag-prefix / default-Flux-v2-per-CR-reconcile-poll-
14959/// cadence / default-Flux-v2-per-CR-kustomization-reconcile-wall-clock-cap
14960/// / default-pleme-io-git-org surfaces onto the sibling default-Flux-v2-
14961/// per-CR-HelmRelease-chart-directory-in-git-source surface every rendered
14962/// per-caixa Flux v2 cluster bundle `HelmRelease` CR carries.
14963///
14964/// [cf]: ../../caixa_flux/index.html
14965/// [fc]: ../../caixa_flux/struct.ClusterBundleOpts.html#method.for_caixa
14966pub const DEFAULT_FLUX_CHART_SOURCE_SUBPATH: &str = "chart";
14967
14968/// Canonical Flux v2 `HelmRelease.spec.{install,upgrade}.remediation.retries`
14969/// bounded retry-count scalar every [`caixa-flux`][cf]-emitted `helmrelease.yaml`
14970/// document declares under both the install-path and the upgrade-path
14971/// `remediation` blocks. The Flux v2 `helm-controller` per-CR `Install` /
14972/// `Upgrade` action reconciler consumes this scalar as the ceiling on the
14973/// number of times it will re-attempt a failed Helm install or Helm upgrade
14974/// before it marks the `HelmRelease` `Ready: False` and stops retrying — the
14975/// substrate's canonical "how many times we let Flux re-try a chart apply
14976/// before it stops" contract with the helm-controller-side per-CR
14977/// remediation loop.
14978///
14979/// The single source of truth all two duplicated inline `retries: 3`
14980/// scalar-value literal sites the substrate's [`cluster_bundle`][cb]
14981/// `helmrelease.yaml` format-string template reaches for:
14982///
14983///   - `helmrelease.yaml` `spec.install.remediation.retries` — the install-
14984///     path retry cap the helm-controller consumes for the first-time chart
14985///     apply the `HelmRelease` CR gates. Before this lift landed the value
14986///     sat as an inline `retries: 3\n` literal inside
14987///     [`cluster_bundle`][cb]'s `helmrelease.yaml` format-string template's
14988///     `install:` sub-block (caixa-flux/src/lib.rs — the `install.remediation`
14989///     sub-block).
14990///   - `helmrelease.yaml` `spec.upgrade.remediation.retries` — the upgrade-
14991///     path retry cap the helm-controller consumes for every subsequent
14992///     chart re-apply the same `HelmRelease` CR gates on a caixa version
14993///     bump. Before this lift landed the value sat as a second inline
14994///     `retries: 3\n` literal inside the same
14995///     [`cluster_bundle`][cb] `helmrelease.yaml` format-string template's
14996///     `upgrade:` sub-block (caixa-flux/src/lib.rs — the `upgrade.remediation`
14997///     sub-block).
14998///   - Every future per-caixa `HelmRelease` renderer the M3.x + M4
14999///     absorption roadmap acknowledges (the future
15000///     `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
15001///     `HelmRelease` synthesis, a future per-cluster override `HelmRelease`
15002///     the operator emits for the observability-collector pipeline).
15003///
15004/// Both existing production-code sites carry the *same* substrate-chosen
15005/// retry ceiling — the value is one canonical policy choice, not two
15006/// independent axes: the operator's "how many chart-apply failures we
15007/// tolerate before Flux stops retrying and surfaces the failure at the
15008/// per-caixa `HelmRelease.status.conditions[]` axis the substrate's
15009/// downstream reconciliation-topology consumer watches". A future
15010/// substrate-side retry-ceiling migration (`3` → `5` once per-caixa
15011/// idempotency invariants tighten and higher-retry recovery from
15012/// transient apiserver / registry / oci-source flakes becomes safe, `3`
15013/// → `1` on hardened per-caixa pipelines where a failed apply should
15014/// escalate to operator-attention rather than mask under further retries,
15015/// `3` → `10` on high-churn dev clusters where transient failures
15016/// dominate) without a coordinated edit on *both* sites would have
15017/// silently split the substrate's canonical retry-ceiling between the
15018/// install-path and the upgrade-path — first-time applies would tolerate
15019/// one ceiling while every subsequent per-version re-apply would tolerate
15020/// another, with no field naming the ceiling-drift root cause far from
15021/// the rebrand commit's source. Lifting the value to caixa-core's render-
15022/// constants block alongside the peer [`DEFAULT_FLUX_RECONCILE_INTERVAL`]
15023/// makes the retry-ceiling axis discipline structural: both sites consult
15024/// the same `u32`, and every future per-CR remediation-retries emitter
15025/// inherits the same value by construction with no opportunity for per-
15026/// path drift.
15027///
15028/// The value is a valid Flux v2 `HelmRelease`-remediation-retries scalar
15029/// (per the upstream Flux v2 `HelmRelease.spec.{install,upgrade}.remediation.retries`
15030/// `OpenAPI` schema — a non-negative integer, `-1` reserved as the sentinel
15031/// for "retry indefinitely" which the substrate opts out of by declaring
15032/// a bounded ceiling): a positive `u32` bounded above by the substrate's
15033/// tolerance for silently-masked chart-apply failures. A future rebrand
15034/// on this lift cannot silently land a negative sentinel by construction:
15035/// the [`flux_helmrelease_remediation_retries_default_is_a_bounded_positive_scalar`]
15036/// pin trips at caixa-core build time on any drift past the typed floor.
15037///
15038/// Pairs with the sibling [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f)
15039/// on the peer canonical-Flux-v2-per-CR-substrate-default surface — the
15040/// reconcile-poll cadence default names how often the helm-controller
15041/// re-evaluates the per-CR desired state, and this remediation-retries
15042/// ceiling names how many times a per-evaluation Helm action is allowed
15043/// to fail-and-retry before the controller stops. Both are substrate-side
15044/// policy choices the operator inherits when the per-caixa
15045/// [`ClusterBundleOpts`][co] doesn't pin an override, and both must move
15046/// together on any coordinated substrate-side Flux v2 per-CR-remediation
15047/// tuning-cycle promotion.
15048///
15049/// Same "the typed constant lives in one place" discipline the
15050/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
15051/// (7197d38) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
15052/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
15053/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) /
15054/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
15055/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f) lifts apply on the peer
15056/// canonical-substrate-default-load-bearing-scalar surface.
15057///
15058/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
15059/// [cf]: ../../caixa_flux/index.html
15060/// [co]: ../../caixa_flux/struct.ClusterBundleOpts.html
15061pub const FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT: u32 = 3;
15062
15063/// Canonical Flux v2 `HelmRelease.spec.{install,upgrade}.remediation.retries`
15064/// leaf scalar-key every `caixa-flux`-emitted `helmrelease.yaml` document
15065/// carries at both its install-path + upgrade-path per-CR remediation
15066/// blocks. Peer to the sibling
15067/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-value
15068/// half of the same `(leaf-key, scalar-value)` per-path retry-cap
15069/// declaration pair — the Flux v2 helm-controller's per-CR remediation
15070/// loop reads the scalar under this exact leaf key, so drift on either
15071/// axis is equally load-bearing (a typo on the leaf-key silently strips
15072/// the retry-cap declaration from the emitted `remediation:` sub-block —
15073/// the helm-controller then falls back to the Flux v2 upstream default
15074/// rather than the substrate's chosen ceiling — with no diagnostic
15075/// naming the leaf-key-drift root cause far from the source
15076/// caixa.lisp / the renderer's format-string template).
15077///
15078/// The single source of truth every rendered Flux bundle axis that
15079/// names the per-path per-CR retry-cap leaf reaches for:
15080///
15081///   - the rendered `helmrelease.yaml` document's
15082///     `spec.install.remediation.retries` scalar-key axis
15083///     (caixa-flux/src/lib.rs — the `cluster_bundle` `helmrelease.yaml`
15084///     format-string template's install-path retry-cap leaf under the
15085///     [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]-valued sub-block);
15086///   - the rendered `helmrelease.yaml` document's
15087///     `spec.upgrade.remediation.retries` scalar-key axis (caixa-flux/src/
15088///     lib.rs — the sibling `cluster_bundle` `helmrelease.yaml` format-
15089///     string template's upgrade-path retry-cap leaf under the same
15090///     [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]-valued sub-block);
15091///   - the two test-fixture navigation sites in caixa-flux's `mod tests`
15092///     that probe the rendered document's `.get("retries")` container
15093///     axis to pin the emitted scalar-value against the sibling
15094///     [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] canonical-scalar
15095///     lift (the install-path + upgrade-path production-emit pins
15096///     [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
15097///     / [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]).
15098///
15099/// Both production emit sites + the two test-fixture navigation sites
15100/// name the same Flux v2 per-path per-CR retry-cap leaf-scalar-key and
15101/// must move together on any hypothetical Flux v3 rename (upstream Flux
15102/// v3 roadmap floats candidates like `attempts` / `maxRetries` /
15103/// `retryCount` in the migration prose — the peer Gateway-API-side
15104/// `spec.rules[].retry.attempts` leaf already uses `attempts` on the
15105/// sibling `GATEWAY_API_KEY_ATTEMPTS` axis, an independent CRD group's
15106/// evolution the two `pub const` declarations stay sibling constants
15107/// against). Until this lift landed the axis carried inline `retries`
15108/// literals across the two production emit sites (caixa-flux/src/lib.rs
15109/// — the two `retries: {retries_default}` sub-block leaf-headers inside
15110/// the `cluster_bundle` `helmrelease.yaml` format-string template) plus
15111/// the two test-fixture navigation sites — four occurrences of the same
15112/// load-bearing Flux-v2-per-CR-retry-cap-leaf-scalar-key convention,
15113/// drift-prone by construction.
15114///
15115/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
15116/// "every recurring shape becomes a generator before it becomes a
15117/// pattern; every pattern becomes a library before it becomes
15118/// duplicated code. The duplication budget is zero.") promotes the
15119/// constant to a typed substrate-side `&'static str` on the same
15120/// trajectory the sibling
15121/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15122/// value half established — extends the discipline from the scalar
15123/// value the leaf holds onto the leaf-key itself, closing the
15124/// `(leaf-key, scalar-value)` pair on both halves. The two render-side
15125/// consumers now thread the same `&'static str` through their format-
15126/// string template via a `{retries_key}` named-arg interpolation so a
15127/// future Flux v3 rebrand lands in one place; every future renderer
15128/// that reaches for the canonical Flux v2 per-CR per-path retry-cap
15129/// leaf-key (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
15130/// materializer's per-Aplicacao `HelmRelease`, a future per-edge
15131/// `HelmRelease` the operator emits for the
15132/// `CiliumClusterwideEnvoyConfig` pipeline, a future `caixa-otel`
15133/// collector-pipeline `HelmRelease`) inherits the same value by
15134/// construction with no opportunity for per-renderer drift.
15135///
15136/// Same "the typed constant lives in one place" discipline the
15137/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) sibling
15138/// scalar-value lift plus the peer [`FLUX_KEY_SOURCE_REF`] (236ef01) /
15139/// [`FLUX_KEY_CHART`] / [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
15140/// [`FLUX_KEY_HEALTH_CHECKS`] container-axis-key lifts apply on the
15141/// peer canonical-Flux-v2-load-bearing-string surface.
15142///
15143/// [cf]: ../../caixa_flux/index.html
15144pub const FLUX_HELMRELEASE_KEY_RETRIES: &str = "retries";
15145
15146/// Canonical Flux v2 `HelmRelease.spec.{install,upgrade}.remediation`
15147/// sub-container-axis-key every `caixa-flux`-emitted `helmrelease.yaml`
15148/// document nests the sibling
15149/// [`FLUX_HELMRELEASE_KEY_RETRIES`] retry-cap leaf-scalar-key under, at
15150/// both the install-path + upgrade-path per-CR remediation blocks. The
15151/// parent-container-axis-key half of the same
15152/// `(container-axis-key, leaf-scalar-key, scalar-value)` per-path
15153/// retry-cap declaration triple the sibling
15154/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-value
15155/// + [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key halves
15156/// closed on the value the leaf holds + the leaf-key itself — this lift
15157/// closes the third and final axis on the same per-path retry-cap
15158/// declaration by extending the discipline from the leaf up to the sub-
15159/// container-axis-key the leaf sits under. The Flux v2 helm-controller
15160/// per-CR remediation loop navigates through this exact sub-container
15161/// axis to reach the retry-cap scalar-key, so drift on this axis is
15162/// equally load-bearing (a typo on the sub-container-axis-key silently
15163/// strips the entire per-path remediation block from the emitted per-CR
15164/// document — the helm-controller then falls back to the Flux v2
15165/// upstream defaults for the whole remediation surface rather than the
15166/// substrate's chosen ceiling, with no diagnostic naming the container-
15167/// axis-key-drift root cause far from the source caixa.lisp / the
15168/// renderer's format-string template).
15169///
15170/// The single source of truth every rendered Flux bundle axis that
15171/// names the per-path per-CR remediation sub-container reaches for:
15172///
15173///   - the rendered `helmrelease.yaml` document's `spec.install.remediation`
15174///     sub-block-header axis (caixa-flux/src/lib.rs — the `cluster_bundle`
15175///     `helmrelease.yaml` format-string template's install-path
15176///     remediation sub-block-header nesting the retry-cap leaf under the
15177///     sibling
15178///     [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]-valued scalar);
15179///   - the rendered `helmrelease.yaml` document's `spec.upgrade.remediation`
15180///     sub-block-header axis (caixa-flux/src/lib.rs — the sibling
15181///     `cluster_bundle` `helmrelease.yaml` format-string template's
15182///     upgrade-path remediation sub-block-header, additionally nesting
15183///     the `remediateLastFailure: true` toggle on the upgrade-path
15184///     sibling axis);
15185///   - the two test-fixture navigation sites in caixa-flux's `mod tests`
15186///     that probe the rendered document's `.get("remediation")` container
15187///     axis to reach the sibling [`FLUX_HELMRELEASE_KEY_RETRIES`] leaf-
15188///     scalar-key pin (the install-path + upgrade-path production-emit
15189///     pins
15190///     [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
15191///     / [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]).
15192///
15193/// Both production emit sites + the two test-fixture navigation sites
15194/// name the same Flux v2 per-path per-CR remediation sub-container-axis
15195/// key and must move together on any hypothetical Flux v3 rename
15196/// (upstream Flux v3 roadmap floats candidates like `recovery` /
15197/// `retryPolicy` / `errorHandling` in the migration prose). Until this
15198/// lift landed the axis carried inline `remediation` literals across the
15199/// two production emit sites (caixa-flux/src/lib.rs — the two
15200/// `remediation:` sub-block-header lines inside the `cluster_bundle`
15201/// `helmrelease.yaml` format-string template's install-path + upgrade-
15202/// path per-CR blocks) plus the two test-fixture navigation sites —
15203/// four occurrences of the same load-bearing Flux-v2-per-CR-remediation-
15204/// sub-container-axis-key convention, drift-prone by construction.
15205///
15206/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
15207/// "every recurring shape becomes a generator before it becomes a
15208/// pattern; every pattern becomes a library before it becomes
15209/// duplicated code. The duplication budget is zero.") promotes the
15210/// constant to a typed substrate-side `&'static str` on the same
15211/// trajectory the sibling [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc)
15212/// leaf-scalar-key half + the sibling
15213/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15214/// value half established — closes the parent-container-axis-key axis
15215/// on the same per-path retry-cap declaration triple, so all three
15216/// halves now live in one place. The two render-side consumers now
15217/// thread the same `&'static str` through their format-string template
15218/// via a `{remediation_key}` named-arg interpolation so a future Flux v3
15219/// rebrand lands in one place; every future renderer that reaches for
15220/// the canonical Flux v2 per-CR per-path remediation sub-container-axis
15221/// key inherits the same value by construction with no opportunity for
15222/// per-renderer drift.
15223///
15224/// Same "the typed constant lives in one place" discipline the sibling
15225/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key half plus
15226/// the peer [`FLUX_KEY_SOURCE_REF`] (236ef01) / [`FLUX_KEY_CHART`] /
15227/// [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
15228/// [`FLUX_KEY_HEALTH_CHECKS`] container-axis-key lifts apply on the
15229/// peer canonical-Flux-v2-load-bearing-string surface.
15230///
15231/// [cf]: ../../caixa_flux/index.html
15232pub const FLUX_HELMRELEASE_KEY_REMEDIATION: &str = "remediation";
15233
15234/// Canonical Flux v2 `HelmRelease.spec.install` per-CR helm-action-phase
15235/// discriminator parent-container-axis-key every `caixa-flux`-emitted
15236/// `helmrelease.yaml` document nests the sibling
15237/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key
15238/// under, at the first-time chart apply per-CR phase the Flux v2 helm-
15239/// controller reconciles when the emitted `HelmRelease` CR first lands in
15240/// the cluster. Pairs with the sibling [`FLUX_HELMRELEASE_KEY_UPGRADE`]
15241/// per-CR helm-action-phase discriminator parent-container-axis-key on
15242/// the peer per-CR upgrade-path phase the helm-controller reconciles on
15243/// every subsequent per-version chart re-apply the same CR gates. The
15244/// Flux v2 helm-controller-side per-CR phase-dispatch loop keys off this
15245/// exact parent-container-axis-key to select the install-path per-CR
15246/// action pipeline (`createNamespace` seeder, first-time chart values
15247/// merge, `spec.install.remediation.retries` retry-cap ceiling under the
15248/// nested [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container), so drift
15249/// on this axis is exactly as load-bearing as drift on the nested
15250/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-axis-key it hosts
15251/// (a `"initialize"` / `"apply"` / `"create"` / `"first-run"` typo at
15252/// the production-code call site silently strips the entire install-path
15253/// per-CR phase block from the emitted per-CR document — the helm-
15254/// controller then falls back to the Flux v2 upstream defaults for the
15255/// whole install-path phase surface rather than the substrate's chosen
15256/// per-CR install-path knob-set — `createNamespace` never fires, the
15257/// per-CR retry-cap ceiling silently drops off the emitted document,
15258/// with no diagnostic naming the phase-discriminator-drift root cause
15259/// far from the source `caixa.lisp` / the renderer's format-string
15260/// template).
15261///
15262/// The single source of truth every rendered Flux bundle axis that names
15263/// the per-CR install-path phase parent-container reaches for:
15264///
15265///   - the rendered `helmrelease.yaml` document's `spec.install` sub-
15266///     block-header axis (caixa-flux/src/lib.rs — the `cluster_bundle`
15267///     `helmrelease.yaml` format-string template's install-path sub-
15268///     block-header nesting the `createNamespace: true` seeder + the
15269///     sibling [`FLUX_HELMRELEASE_KEY_REMEDIATION`]-container-keyed
15270///     retry-cap sub-block);
15271///   - the test-fixture navigation site in caixa-flux's `mod tests` that
15272///     probes the rendered document's `.get("install")` container axis
15273///     to reach the sibling [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-
15274///     container (the install-path production-emit pin
15275///     [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]).
15276///
15277/// Both the production emit site + the test-fixture navigation site name
15278/// the same Flux v2 per-CR install-path helm-action-phase discriminator
15279/// parent-container-axis-key and must move together on any hypothetical
15280/// Flux v3 rename (upstream Flux v3 roadmap floats candidates like
15281/// `initialize` / `apply` / `create` / `first-run` in the migration
15282/// prose). Until this lift landed the axis carried inline `install`
15283/// literals across the one production emit site (caixa-flux/src/lib.rs —
15284/// the `install:` sub-block-header line inside the `cluster_bundle`
15285/// `helmrelease.yaml` format-string template's per-CR install-path block)
15286/// plus the one test-fixture navigation site — two occurrences of the
15287/// same load-bearing Flux-v2-per-CR-install-path-phase-discriminator-
15288/// parent-container-axis-key convention, drift-prone by construction.
15289///
15290/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
15291/// recurring shape becomes a generator before it becomes a pattern; every
15292/// pattern becomes a library before it becomes duplicated code. The
15293/// duplication budget is zero.") promotes the constant to a typed
15294/// substrate-side `&'static str` on the same trajectory the sibling
15295/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
15296/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key +
15297/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15298/// value halves of the same `(parent-container-key, sub-container-key,
15299/// leaf-key, scalar-value)` per-path retry-cap declaration quartet
15300/// established — extends the discipline from the sub-container-axis-key
15301/// one level up to the parent-container-axis-key hosting it, so the
15302/// four-level nested `spec.install.remediation.retries` declaration now
15303/// resolves through four lifted `&'static str` / `u32` values. Companion
15304/// to the sibling [`FLUX_HELMRELEASE_KEY_UPGRADE`] per-CR upgrade-path
15305/// phase-discriminator parent-container-axis-key on the peer per-CR
15306/// helm-action-phase surface — completes the per-CR helm-action-phase
15307/// discriminator parent-container-axis-key pair the Flux v2 helm-
15308/// controller reconciles between at first-time chart apply time
15309/// (install-path phase) vs. every subsequent per-version chart re-apply
15310/// (upgrade-path phase).
15311///
15312/// Same "the typed constant lives in one place" discipline the sibling
15313/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
15314/// the peer [`FLUX_KEY_SOURCE_REF`] (236ef01) / [`FLUX_KEY_CHART`] /
15315/// [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
15316/// [`FLUX_KEY_HEALTH_CHECKS`] per-CR container-axis-key lifts apply on
15317/// the peer canonical-Flux-v2-load-bearing-string surface.
15318///
15319/// [cf]: ../../caixa_flux/index.html
15320pub const FLUX_HELMRELEASE_KEY_INSTALL: &str = "install";
15321
15322/// Canonical Flux v2 `HelmRelease.spec.upgrade` per-CR helm-action-phase
15323/// discriminator parent-container-axis-key every `caixa-flux`-emitted
15324/// `helmrelease.yaml` document nests the sibling
15325/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key
15326/// under, at every subsequent per-version chart re-apply per-CR phase the
15327/// Flux v2 helm-controller reconciles after the initial install-path
15328/// phase completes. Pairs with the sibling
15329/// [`FLUX_HELMRELEASE_KEY_INSTALL`] per-CR helm-action-phase discriminator
15330/// parent-container-axis-key on the peer per-CR install-path phase the
15331/// helm-controller reconciles at first-time chart apply. The Flux v2
15332/// helm-controller-side per-CR phase-dispatch loop keys off this exact
15333/// parent-container-axis-key to select the upgrade-path per-CR action
15334/// pipeline (`remediateLastFailure` toggle the substrate pins to `true`
15335/// on the upgrade-path per-CR sibling axis, the per-CR retry-cap ceiling
15336/// under the nested [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container),
15337/// so drift on this axis is exactly as load-bearing as drift on the
15338/// nested [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-axis-key it
15339/// hosts (a `"reapply"` / `"reconcile"` / `"update"` / `"promote"` typo
15340/// at the production-code call site silently strips the entire upgrade-
15341/// path per-CR phase block from the emitted per-CR document — the helm-
15342/// controller then falls back to the Flux v2 upstream defaults for the
15343/// whole upgrade-path phase surface rather than the substrate's chosen
15344/// per-CR upgrade-path knob-set — `remediateLastFailure` never fires, the
15345/// per-CR retry-cap ceiling silently drops off the emitted document, with
15346/// no diagnostic naming the phase-discriminator-drift root cause far
15347/// from the source `caixa.lisp` / the renderer's format-string template).
15348///
15349/// The single source of truth every rendered Flux bundle axis that names
15350/// the per-CR upgrade-path phase parent-container reaches for:
15351///
15352///   - the rendered `helmrelease.yaml` document's `spec.upgrade` sub-
15353///     block-header axis (caixa-flux/src/lib.rs — the `cluster_bundle`
15354///     `helmrelease.yaml` format-string template's upgrade-path sub-
15355///     block-header nesting the substrate's `remediateLastFailure: true`
15356///     toggle + the sibling [`FLUX_HELMRELEASE_KEY_REMEDIATION`]-
15357///     container-keyed retry-cap sub-block);
15358///   - the test-fixture navigation site in caixa-flux's `mod tests` that
15359///     probes the rendered document's `.get("upgrade")` container axis to
15360///     reach the sibling [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-
15361///     container (the upgrade-path production-emit pin
15362///     [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]).
15363///
15364/// Both the production emit site + the test-fixture navigation site name
15365/// the same Flux v2 per-CR upgrade-path helm-action-phase discriminator
15366/// parent-container-axis-key and must move together on any hypothetical
15367/// Flux v3 rename (upstream Flux v3 roadmap floats candidates like
15368/// `reapply` / `reconcile` / `update` / `promote` in the migration
15369/// prose). Until this lift landed the axis carried inline `upgrade`
15370/// literals across the one production emit site plus the one test-
15371/// fixture navigation site — two occurrences of the same load-bearing
15372/// Flux-v2-per-CR-upgrade-path-phase-discriminator-parent-container-
15373/// axis-key convention, drift-prone by construction.
15374///
15375/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
15376/// recurring shape becomes a generator before it becomes a pattern; every
15377/// pattern becomes a library before it becomes duplicated code. The
15378/// duplication budget is zero.") promotes the constant to a typed
15379/// substrate-side `&'static str` on the same trajectory the sibling
15380/// [`FLUX_HELMRELEASE_KEY_INSTALL`] per-CR install-path phase-
15381/// discriminator parent-container-axis-key +
15382/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
15383/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key +
15384/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15385/// value halves of the same `(parent-container-key, sub-container-key,
15386/// leaf-key, scalar-value)` per-path retry-cap declaration quartet
15387/// established — pairs with the [`FLUX_HELMRELEASE_KEY_INSTALL`]
15388/// mandatory-arm parent-container-axis-key to close the per-CR helm-
15389/// action-phase discriminator parent-container-axis-key pair across
15390/// both per-CR phases the helm-controller reconciles between (install-
15391/// path at first-time chart apply, upgrade-path at every subsequent
15392/// per-version chart re-apply).
15393///
15394/// Same "the typed constant lives in one place" discipline the sibling
15395/// [`FLUX_HELMRELEASE_KEY_INSTALL`] per-CR install-path-phase-
15396/// discriminator + [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-
15397/// container-axis-key + the peer [`FLUX_KEY_SOURCE_REF`] (236ef01) /
15398/// [`FLUX_KEY_CHART`] / [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
15399/// [`FLUX_KEY_HEALTH_CHECKS`] per-CR container-axis-key lifts apply on
15400/// the peer canonical-Flux-v2-load-bearing-string surface.
15401///
15402/// [cf]: ../../caixa_flux/index.html
15403pub const FLUX_HELMRELEASE_KEY_UPGRADE: &str = "upgrade";
15404
15405/// Canonical Flux v2 `HelmRelease.spec.upgrade.remediation.remediateLastFailure`
15406/// upgrade-path-only per-CR remediation-toggle leaf-scalar-key every
15407/// `caixa-flux`-emitted `helmrelease.yaml` document seeds to `true` under
15408/// the sibling [`FLUX_HELMRELEASE_KEY_UPGRADE`] per-CR upgrade-path phase-
15409/// discriminator parent-container-axis-key's nested
15410/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-axis-key. Sibling to
15411/// the peer [`FLUX_HELMRELEASE_KEY_RETRIES`] retry-cap leaf-scalar-key at
15412/// the same per-CR upgrade-path per-CR remediation sub-container position —
15413/// closes the `spec.upgrade.remediation.{retries, remediateLastFailure}`
15414/// per-path remediation-block leaf-scalar-key pair the substrate seeds into
15415/// every emitted per-caixa `HelmRelease` CR on the upgrade-path per-CR
15416/// remediation block, with retries capping the per-version chart re-apply
15417/// retry-count and remediateLastFailure gating the "the Flux v2 helm-
15418/// controller must actively remediate — roll back to the prior success —
15419/// when the final per-version chart re-apply attempt still fails" post-
15420/// retry-exhaustion behavior. The Flux v2 helm-controller-side per-CR
15421/// upgrade-path remediation loop keys off this exact leaf to decide
15422/// whether to leave a failed upgrade in place (`false`) or trigger the
15423/// prior-release rollback pipeline (`true`); drift on this axis silently
15424/// drops the substrate's chosen post-retry-exhaustion rollback semantic
15425/// from every emitted per-caixa `HelmRelease` document (the helm-
15426/// controller then leaves every terminally-failed upgrade in the failed
15427/// state without rolling back to the prior last-known-good release the
15428/// substrate's "no chart apply leaves a per-caixa CR in a stalled,
15429/// unremediated state" MESH-COMPOSITION.md §V guarantee mandates — with
15430/// no diagnostic naming the remediation-toggle-drift root cause far from
15431/// the source `caixa.lisp` / the renderer's format-string template).
15432///
15433/// Note the axis is asymmetric across the peer install-path per-CR
15434/// remediation block: the substrate emits the toggle only under
15435/// `spec.upgrade.remediation` and not under `spec.install.remediation`
15436/// because the Flux v2 helm-controller's install-path per-CR remediation
15437/// loop treats a failed first-time chart apply as an uninstall-and-retry
15438/// pipeline whose "prior success" state is the empty pre-install cluster
15439/// state — the "roll back to the prior success" post-retry-exhaustion
15440/// behavior the toggle gates is well-defined only on the upgrade-path
15441/// where the prior success is a previous chart-version release, which is
15442/// why the [`FLUX_HELMRELEASE_KEY_RETRIES`] retry-cap leaf-scalar-key
15443/// sits under both per-CR remediation sub-containers (retry-cap applies
15444/// on both paths) but this per-CR remediation-toggle leaf-scalar-key
15445/// sits under the upgrade-path per-CR remediation sub-container only.
15446///
15447/// The single source of truth every rendered Flux bundle axis that names
15448/// the upgrade-path per-CR remediation-toggle leaf reaches for:
15449///
15450///   - the rendered `helmrelease.yaml` document's
15451///     `spec.upgrade.remediation.remediateLastFailure` leaf-scalar-key
15452///     axis (caixa-flux/src/lib.rs — the `cluster_bundle` `helmrelease
15453///     .yaml` format-string template's upgrade-path remediation-toggle
15454///     leaf under the [`FLUX_HELMRELEASE_KEY_REMEDIATION`]-container-keyed
15455///     sub-block, threading the same `&'static str` through a new
15456///     `{remediate_last_failure_key}` named-arg interpolation);
15457///   - the one test-fixture navigation site in caixa-flux's `mod tests`
15458///     that probes the rendered document's `.get("remediateLastFailure")`
15459///     leaf axis to pin the substrate's canonical `true` seed
15460///     (the [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
15461///     upgrade-path production-emit pin).
15462///
15463/// Both the production emit site + the one test-fixture navigation site
15464/// name the same Flux v2 per-CR upgrade-path remediation-toggle leaf-
15465/// scalar-key and must move together on any hypothetical Flux v3 rename
15466/// (upstream Flux v3 roadmap floats candidates like
15467/// `rollbackOnFailure` / `remediateOnFailure` / `recoverLastFailure` in
15468/// the migration prose). Until this lift landed the axis carried inline
15469/// `remediateLastFailure` literals across the one production emit site
15470/// (caixa-flux/src/lib.rs — the `remediateLastFailure: true` leaf inside
15471/// the `cluster_bundle` `helmrelease.yaml` format-string template's per-
15472/// CR upgrade-path remediation sub-block) — the sole occurrence of the
15473/// same load-bearing Flux-v2-per-CR-upgrade-path-remediation-toggle-
15474/// leaf-scalar-key convention, drift-prone by construction ahead of the
15475/// second occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
15476/// materializer's per-Aplicacao `HelmRelease` synthesis will surface,
15477/// where a per-renderer local `pub const FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE:
15478/// &str = "…"` (the canonical drift footgun where a sibling local
15479/// `pub const` could happen to carry the same string at the source while
15480/// pointing at a different `&'static` allocation) would let the two
15481/// renderers silently disagree on the post-retry-exhaustion remediation
15482/// semantic.
15483///
15484/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
15485/// recurring shape becomes a generator before it becomes a pattern; every
15486/// pattern becomes a library before it becomes duplicated code. The
15487/// duplication budget is zero.") promotes the constant to a typed
15488/// substrate-side `&'static str` in advance of the second occurrence the
15489/// M4 materializer will surface — so the second consumer inherits the
15490/// canonical upgrade-path per-CR remediation-toggle leaf-scalar-key by
15491/// construction without opportunity for per-renderer drift.
15492///
15493/// Same "the typed constant lives in one place" discipline the sibling
15494/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key +
15495/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
15496/// [`FLUX_HELMRELEASE_KEY_INSTALL`] / [`FLUX_HELMRELEASE_KEY_UPGRADE`]
15497/// (7767c26) parent-container-axis-key pair +
15498/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15499/// value halves of the per-path per-CR remediation surface established —
15500/// closes the sibling upgrade-path-only per-CR remediation-toggle leaf-
15501/// scalar-key half at the same `spec.upgrade.remediation.*` position the
15502/// retries leaf sits at.
15503///
15504/// [cf]: ../../caixa_flux/index.html
15505pub const FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE: &str = "remediateLastFailure";
15506
15507/// Canonical Flux v2 `HelmRelease.spec.upgrade.remediation.remediateLastFailure`
15508/// upgrade-path-only per-CR remediation-toggle scalar-value default the
15509/// substrate seeds into every per-caixa `helmrelease.yaml` document at the
15510/// paired [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] leaf-scalar-key
15511/// axis. Pairs with the sibling [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`]
15512/// (96581b7) leaf-scalar-key half of the same `(leaf-key, scalar-value)`
15513/// per-CR upgrade-path per-CR post-retry-exhaustion-rollback-toggle
15514/// declaration pair — the Flux v2 helm-controller's per-CR upgrade-path
15515/// remediation loop reads the scalar under that exact leaf key to decide
15516/// whether to trigger the prior-release rollback pipeline once the paired
15517/// [`FLUX_HELMRELEASE_KEY_RETRIES`] retry-cap ceiling has been exhausted,
15518/// so drift on either axis is equally load-bearing (a rebrand on this
15519/// canonical scalar-value default that failed to reach every renderer's
15520/// emit site would silently split the substrate's chosen post-retry-
15521/// exhaustion rollback semantic between the operator-facing canonical
15522/// default and every per-caixa `HelmRelease` document's per-CR upgrade-
15523/// path remediation-toggle, with no field naming the semantic-drift root
15524/// cause far from the source `caixa.lisp` / the renderer's format-string
15525/// template).
15526///
15527/// The `true` seed opts every emitted per-caixa `HelmRelease` into the
15528/// substrate's canonical "no chart apply leaves a per-caixa CR in a
15529/// stalled, unremediated state" semantic (MESH-COMPOSITION.md §V): once
15530/// the paired [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] retry-cap
15531/// ceiling is exhausted on the upgrade-path per-CR reconcile loop the
15532/// helm-controller rolls the per-caixa release back to the prior last-
15533/// known-good `HelmRelease.status.lastAppliedRevision` snapshot rather
15534/// than leaving the per-caixa `HelmRelease` parked at `Ready: False`
15535/// with no forward-progress on the substrate's per-caixa reconciliation
15536/// topology. A future substrate-side rebrand to `false` (or a per-caixa
15537/// opt-out slot the ABSORPTION-ROADMAP.md M4 typed-slot trajectory adds
15538/// once the substrate grows a `:upgrade :remediate-last-failure` author-
15539/// side toggle) is a one-line edit on this canonical declaration, not a
15540/// coordinated rewrite across every future per-target renderer the
15541/// substrate adds. Peer with the sibling
15542/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) scalar-value default on
15543/// the peer canonical-Flux-v2-per-CR-substrate-default surface — the
15544/// garbage-collection-toggle default names whether the per-CR
15545/// `Kustomization` reconcile loop sweeps orphaned resources at all, and
15546/// this remediation-toggle default names whether the per-CR `HelmRelease`
15547/// upgrade-path remediation loop rolls back to the prior last-known-good
15548/// release once the retry-cap ceiling is exhausted. Both are substrate-
15549/// side policy choices the operator inherits when the per-caixa
15550/// [`ClusterBundleOpts`][co] doesn't pin an override, and both must move
15551/// together on any coordinated substrate-side Flux v2 per-CR
15552/// tuning-cycle promotion.
15553///
15554/// The single source of truth every rendered Flux bundle axis that
15555/// names the per-CR upgrade-path remediation-toggle scalar reaches for:
15556///
15557///   - the rendered `helmrelease.yaml` document's
15558///     `spec.upgrade.remediation.remediateLastFailure` scalar-value axis
15559///     (caixa-flux/src/lib.rs — the [`cluster_bundle`][cb]
15560///     `helmrelease.yaml` format-string template's per-CR upgrade-path
15561///     remediation-toggle scalar under the
15562///     [`FLUX_HELMRELEASE_KEY_UPGRADE`]-keyed sub-block, threading the
15563///     same `bool` through a `{remediate_last_failure_default}` named-arg
15564///     interpolation);
15565///   - the one test-fixture navigation site in caixa-flux's `mod tests`
15566///     that probes the rendered document's
15567///     `.get("remediateLastFailure")` scalar axis to pin the substrate's
15568///     canonical `true` seed against the lifted default (the
15569///     [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
15570///     per-CR production-emit pin).
15571///
15572/// Both the production emit site + the one test-fixture navigation site
15573/// now consume the same `bool` at emit time through the sibling
15574/// re-export [`caixa_flux::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`][cf],
15575/// so a future substrate-side toggle migration on the canonical scalar-
15576/// value axis reaches every consumer through one `bool` by construction —
15577/// with no opportunity for per-renderer drift where a rebrand on one
15578/// axis without a coordinated edit on the other would silently disagree
15579/// on the post-retry-exhaustion rollback semantic. Until this lift
15580/// landed the axis carried an inline `true` scalar-value literal at the
15581/// sole production-code call site (the `remediateLastFailure: true` leaf
15582/// inside the [`cluster_bundle`][cb] `helmrelease.yaml` format-string
15583/// template's per-CR `spec.upgrade.remediation` sub-block) plus the
15584/// sibling test-fixture navigation site — two occurrences of the same
15585/// load-bearing Flux-v2-per-CR-upgrade-path-remediation-toggle-scalar-
15586/// value convention, drift-prone by construction ahead of the third
15587/// occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
15588/// per-Aplicacao `HelmRelease` synthesis will surface, where a per-
15589/// renderer local `pub const FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT: bool = …`
15590/// at any downstream renderer would let the two consumers silently
15591/// disagree on the substrate's canonical seed.
15592///
15593/// Same "the typed constant lives in one place" discipline the
15594/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
15595/// (7197d38) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
15596/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
15597/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) /
15598/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
15599/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f) /
15600/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) /
15601/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) lifts apply on the peer
15602/// canonical-substrate-default-load-bearing-scalar surface.
15603///
15604/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
15605/// [cf]: ../../caixa_flux/index.html
15606/// [co]: ../../caixa_flux/struct.ClusterBundleOpts.html
15607pub const FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT: bool = true;
15608
15609/// Canonical Flux v2 `HelmRelease.spec.install.createNamespace` install-path-
15610/// only per-CR namespace-seeder-toggle leaf-scalar-key every `caixa-flux`-
15611/// emitted `helmrelease.yaml` document seeds to `true` under the sibling
15612/// [`FLUX_HELMRELEASE_KEY_INSTALL`] per-CR install-path phase-discriminator
15613/// parent-container-axis-key. Peer to the sibling
15614/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] upgrade-path-only per-CR
15615/// remediation-toggle leaf-scalar-key at the co-resident per-CR install/
15616/// upgrade phase-discriminator parent-container position — closes the
15617/// `spec.{install.createNamespace, upgrade.remediation.remediateLastFailure}`
15618/// per-path per-CR phase-specific toggle leaf-scalar-key pair the substrate
15619/// seeds into every emitted per-caixa `HelmRelease` CR: `createNamespace`
15620/// gates the "the Flux v2 helm-controller creates the target namespace
15621/// itself if the emitted `HelmRelease.metadata.namespace` (or its
15622/// `spec.targetNamespace` override) does not already exist" install-path
15623/// pre-apply seeder pipeline, while `remediateLastFailure` gates the
15624/// upgrade-path post-retry-exhaustion rollback pipeline. The Flux v2 helm-
15625/// controller-side per-CR install-path pre-apply loop keys off this exact
15626/// leaf to decide whether to first materialize the target namespace or
15627/// refuse the first-time chart apply when the target namespace does not
15628/// yet exist (`false`); drift on this axis silently drops the substrate's
15629/// chosen first-apply namespace-seeder semantic from every emitted per-
15630/// caixa `HelmRelease` document (the helm-controller then refuses every
15631/// first-time per-caixa chart apply against a fresh cluster whose target
15632/// namespace has not been pre-provisioned by an out-of-band pipeline —
15633/// the substrate's "no per-caixa Servico apply is blocked on manual
15634/// namespace preprovisioning" MESH-COMPOSITION.md §V install-path-fluency
15635/// guarantee silently regresses, with no diagnostic naming the seeder-
15636/// toggle-drift root cause far from the source `caixa.lisp` / the
15637/// renderer's format-string template).
15638///
15639/// Note the axis is asymmetric across the peer upgrade-path per-CR phase
15640/// block: the substrate emits the toggle only under `spec.install` and not
15641/// under `spec.upgrade` because the Flux v2 helm-controller's upgrade-path
15642/// per-CR reconcile loop presupposes the target namespace already carries
15643/// the prior release's resources (the upgrade-path is by definition a
15644/// re-apply against an already-materialized namespace whose pre-apply
15645/// seeding was resolved at the sibling install-path phase's first-time
15646/// apply), so the "seed the target namespace if it does not already exist"
15647/// pre-apply behavior the toggle gates is well-defined only on the
15648/// install-path where the target namespace's existence is not yet
15649/// established. This is the mirror of the peer sibling
15650/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] axis, which is
15651/// upgrade-path-only for the mirror reason (the "roll back to the prior
15652/// success" post-retry-exhaustion behavior is well-defined only on the
15653/// upgrade-path where a prior success exists) — the two per-CR phase-
15654/// specific toggle leaf-scalar-keys sit under mirror-symmetric
15655/// parent-container-axis-keys and together close the install/upgrade
15656/// phase-block per-CR-phase-specific toggle leaf-scalar-key pair.
15657///
15658/// The single source of truth every rendered Flux bundle axis that names
15659/// the install-path per-CR namespace-seeder-toggle leaf reaches for:
15660///
15661///   - the rendered `helmrelease.yaml` document's
15662///     `spec.install.createNamespace` leaf-scalar-key axis
15663///     (caixa-flux/src/lib.rs — the `cluster_bundle` `helmrelease.yaml`
15664///     format-string template's install-path namespace-seeder-toggle leaf
15665///     under the [`FLUX_HELMRELEASE_KEY_INSTALL`]-container-keyed sub-block,
15666///     threading the same `&'static str` through a new
15667///     `{create_namespace_key}` named-arg interpolation);
15668///   - the one test-fixture navigation site in caixa-flux's `mod tests`
15669///     that probes the rendered document's `.get("createNamespace")` leaf
15670///     axis to pin the substrate's canonical `true` seed
15671///     (the [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
15672///     install-path production-emit pin).
15673///
15674/// Both the production emit site + the one test-fixture navigation site
15675/// name the same Flux v2 per-CR install-path namespace-seeder-toggle leaf-
15676/// scalar-key and must move together on any hypothetical Flux v3 rename
15677/// (upstream Flux v3 roadmap floats candidates like `createTargetNamespace`
15678/// / `seedNamespace` / `provisionNamespace` in the migration prose). Until
15679/// this lift landed the axis carried inline `createNamespace` literals
15680/// across the one production emit site (caixa-flux/src/lib.rs — the
15681/// `createNamespace: true` leaf inside the `cluster_bundle` `helmrelease
15682/// .yaml` format-string template's per-CR install-path sub-block) — the
15683/// sole occurrence of the same load-bearing Flux-v2-per-CR-install-path-
15684/// namespace-seeder-toggle-leaf-scalar-key convention, drift-prone by
15685/// construction ahead of the second occurrence the M4
15686/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
15687/// `HelmRelease` synthesis will surface, where a per-renderer local
15688/// `pub const FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE: &str = "…"` (the
15689/// canonical drift footgun where a sibling local `pub const` could happen
15690/// to carry the same string at the source while pointing at a different
15691/// `&'static` allocation) would let the two renderers silently disagree on
15692/// the install-path namespace-seeder semantic.
15693///
15694/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5, "every
15695/// recurring shape becomes a generator before it becomes a pattern; every
15696/// pattern becomes a library before it becomes duplicated code. The
15697/// duplication budget is zero.") promotes the constant to a typed
15698/// substrate-side `&'static str` in advance of the second occurrence the
15699/// M4 materializer will surface — so the second consumer inherits the
15700/// canonical install-path per-CR namespace-seeder-toggle leaf-scalar-key
15701/// by construction without opportunity for per-renderer drift.
15702///
15703/// Same "the typed constant lives in one place" discipline the sibling
15704/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7) upgrade-path-
15705/// only per-CR remediation-toggle leaf-scalar-key +
15706/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key +
15707/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
15708/// [`FLUX_HELMRELEASE_KEY_INSTALL`] / [`FLUX_HELMRELEASE_KEY_UPGRADE`]
15709/// (7767c26) parent-container-axis-key pair +
15710/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-value
15711/// halves of the per-path per-CR HelmRelease spec surface established —
15712/// closes the mirror install-path-only per-CR namespace-seeder-toggle
15713/// leaf-scalar-key half at the `spec.install.createNamespace` position the
15714/// peer `spec.upgrade.remediation.remediateLastFailure` upgrade-path-only
15715/// per-CR remediation-toggle leaf mirrors.
15716///
15717/// [cf]: ../../caixa_flux/index.html
15718pub const FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE: &str = "createNamespace";
15719
15720/// Canonical Flux v2 `HelmRelease.spec.install.createNamespace` install-path-
15721/// only per-CR namespace-seeder-toggle scalar-value default the substrate
15722/// seeds into every per-caixa `helmrelease.yaml` document at the paired
15723/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] leaf-scalar-key axis. Pairs
15724/// with the sibling [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b)
15725/// leaf-scalar-key half of the same `(leaf-key, scalar-value)` per-CR
15726/// install-path per-CR namespace-seeder-toggle declaration pair — the
15727/// Flux v2 helm-controller's per-CR install-path pre-apply loop reads
15728/// the scalar under that exact leaf key to decide whether to first
15729/// materialize the target namespace before the first-time chart apply,
15730/// so drift on either axis is equally load-bearing (a rebrand on this
15731/// canonical scalar-value default that failed to reach every renderer's
15732/// emit site would silently split the substrate's chosen first-apply
15733/// namespace-seeder semantic between the operator-facing canonical
15734/// default and every per-caixa `HelmRelease` document's per-CR install-
15735/// path namespace-seeder-toggle, with no field naming the semantic-drift
15736/// root cause far from the source `caixa.lisp` / the renderer's format-
15737/// string template).
15738///
15739/// The `true` seed opts every emitted per-caixa `HelmRelease` into the
15740/// substrate's canonical "no per-caixa Servico apply is blocked on
15741/// manual namespace preprovisioning" semantic (MESH-COMPOSITION.md §V
15742/// install-path-fluency guarantee): on every first-time per-caixa chart
15743/// apply the helm-controller first materializes the target namespace
15744/// itself if the emitted `HelmRelease.metadata.namespace` (or its
15745/// `spec.targetNamespace` override) does not already exist, rather than
15746/// refusing the apply and requiring an out-of-band pipeline to have
15747/// pre-provisioned the namespace. A future substrate-side rebrand to
15748/// `false` (or a per-caixa opt-out slot the ABSORPTION-ROADMAP.md M4
15749/// typed-slot trajectory adds once the substrate grows a `:install
15750/// :create-namespace` author-side toggle) is a one-line edit on this
15751/// canonical declaration, not a coordinated rewrite across every future
15752/// per-target renderer the substrate adds. Peer with the sibling
15753/// [`FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`] mirror-symmetric
15754/// upgrade-path-only scalar-value default + the peer
15755/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) scalar-value default on
15756/// the peer canonical-Flux-v2-per-CR-substrate-default surface — the
15757/// three defaults name the substrate's canonical (install-path
15758/// namespace-seeder) / (upgrade-path post-retry-exhaustion rollback) /
15759/// (garbage-collection-toggle) toggle triple across the per-caixa
15760/// `HelmRelease` and `Kustomization` co-resident CRs. All three are
15761/// substrate-side policy choices the operator inherits when the per-
15762/// caixa [`ClusterBundleOpts`][co] doesn't pin an override, and all
15763/// three must move together on any coordinated substrate-side Flux v2
15764/// per-CR tuning-cycle promotion.
15765///
15766/// The single source of truth every rendered Flux bundle axis that
15767/// names the per-CR install-path namespace-seeder-toggle scalar reaches
15768/// for:
15769///
15770///   - the rendered `helmrelease.yaml` document's
15771///     `spec.install.createNamespace` scalar-value axis
15772///     (caixa-flux/src/lib.rs — the [`cluster_bundle`][cb]
15773///     `helmrelease.yaml` format-string template's per-CR install-path
15774///     namespace-seeder-toggle scalar under the
15775///     [`FLUX_HELMRELEASE_KEY_INSTALL`]-keyed sub-block, threading the
15776///     same `bool` through a `{create_namespace_default}` named-arg
15777///     interpolation);
15778///   - the one test-fixture navigation site in caixa-flux's `mod tests`
15779///     that probes the rendered document's `.get("createNamespace")`
15780///     scalar axis to pin the substrate's canonical `true` seed against
15781///     the lifted default (the
15782///     [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
15783///     per-CR production-emit pin).
15784///
15785/// Both the production emit site + the one test-fixture navigation site
15786/// now consume the same `bool` at emit time through the sibling
15787/// re-export [`caixa_flux::FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`][cf],
15788/// so a future substrate-side toggle migration on the canonical scalar-
15789/// value axis reaches every consumer through one `bool` by construction —
15790/// with no opportunity for per-renderer drift where a rebrand on one
15791/// axis without a coordinated edit on the other would silently disagree
15792/// on the first-apply namespace-seeder semantic. Until this lift landed
15793/// the axis carried an inline `true` scalar-value literal at the sole
15794/// production-code call site (the `createNamespace: true` leaf inside
15795/// the [`cluster_bundle`][cb] `helmrelease.yaml` format-string
15796/// template's per-CR `spec.install` sub-block) plus the sibling test-
15797/// fixture navigation site — two occurrences of the same load-bearing
15798/// Flux-v2-per-CR-install-path-namespace-seeder-toggle-scalar-value
15799/// convention, drift-prone by construction ahead of the third occurrence
15800/// the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-
15801/// Aplicacao `HelmRelease` synthesis will surface, where a per-renderer
15802/// local `pub const FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT: bool = …`
15803/// at any downstream renderer would let the two consumers silently
15804/// disagree on the substrate's canonical seed.
15805///
15806/// Same "the typed constant lives in one place" discipline the
15807/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
15808/// (7197d38) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
15809/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
15810/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) /
15811/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
15812/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f) /
15813/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) /
15814/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) /
15815/// [`FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`] lifts apply on
15816/// the peer canonical-substrate-default-load-bearing-scalar surface.
15817///
15818/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
15819/// [cf]: ../../caixa_flux/index.html
15820/// [co]: ../../caixa_flux/struct.ClusterBundleOpts.html
15821pub const FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT: bool = true;
15822
15823/// Canonical Flux v2 `Kustomization.spec.prune` per-CR garbage-collection-
15824/// toggle leaf-scalar-key every `caixa-flux`-emitted `kustomization.yaml`
15825/// document seeds to `true` at the top-level `spec` position of the
15826/// emitted [`Kustomization`][kust] CR. The Flux v2 kustomize-controller-
15827/// side per-CR reconcile loop keys off this exact leaf to decide whether
15828/// to garbage-collect resources that were previously reconciled by the
15829/// CR but no longer appear in the CR's current desired-state manifest set
15830/// (`spec.prune: true` opts every emitted per-caixa `Kustomization` into
15831/// the substrate's canonical GitOps-side sweep-what-you-removed semantic;
15832/// `spec.prune: false` (or absent — Flux v2 defaults the axis to `false`
15833/// on any CR that omits the leaf) leaves orphaned resources dangling in
15834/// the cluster after the source manifest set removes them, silently
15835/// splitting per-caixa live cluster state from the caixa's tatara-lisp
15836/// source-of-truth and every downstream `feira app deploy` / `feira
15837/// deploy` reconcile the substrate's per-caixa GitOps pipeline emits).
15838///
15839/// Drift on this axis silently drops the substrate's chosen sweep-what-
15840/// you-removed semantic from every emitted per-caixa `Kustomization`
15841/// document — the kustomize-controller then leaves every per-caixa
15842/// resource the source manifest set previously reconciled but no longer
15843/// carries dangling in the cluster with no diagnostic naming the toggle-
15844/// drift root cause far from the source `caixa.lisp` / the renderer's
15845/// format-string template, and the substrate's "the cluster's per-caixa
15846/// live state converges to the caixa's tatara-lisp source-of-truth on
15847/// every reconcile — resources the source no longer carries are swept
15848/// by the kustomize-controller, not left dangling" CAIXA-SDLC.md §V
15849/// author-to-live-convergence guarantee silently regresses.
15850///
15851/// Note the axis is asymmetric across the co-resident `HelmRelease` CR:
15852/// the peer `HelmRelease` document seeds no `spec.prune` leaf because
15853/// the Flux v2 helm-controller-side per-CR reconcile loop keys off Helm
15854/// 3's own release-scoped resource-tracking manifest (the per-release
15855/// `helm.sh/release-name` label + `secrets/sh.helm.release.v1.*` release
15856/// snapshots) to garbage-collect resources removed between chart
15857/// versions rather than a CR-level toggle, so the `spec.prune` leaf is
15858/// well-defined only on the `Kustomization` CR whose kustomize-controller
15859/// reconcile loop tracks resources by the CR's manifest set rather than
15860/// Helm's per-release snapshots. This is the mirror of the peer sibling
15861/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] axis, which is `HelmRelease`-
15862/// CR-only for the mirror reason (Helm 3's chart-side `Chart.yaml`
15863/// declares no target-namespace-creation semantic of its own, so the
15864/// helm-controller carries a per-CR toggle at `spec.install.createNamespace`
15865/// that the peer kustomize-controller has no need to mirror since the
15866/// upstream Kustomize project's per-CR spec block establishes the
15867/// target-namespace independently at each `kustomization.yaml` document's
15868/// own `metadata.namespace` axis).
15869///
15870/// The single source of truth every rendered Flux bundle axis that names
15871/// the per-CR garbage-collection-toggle leaf reaches for:
15872///
15873///   - the rendered `kustomization.yaml` document's `spec.prune` leaf-
15874///     scalar-key axis (caixa-flux/src/lib.rs — the `cluster_bundle`
15875///     `kustomization.yaml` format-string template's per-CR garbage-
15876///     collection-toggle leaf under the top-level `spec` position,
15877///     threading the same `&'static str` through a new `{prune_key}`
15878///     named-arg interpolation);
15879///   - the one test-fixture navigation site in caixa-flux's `mod tests`
15880///     that probes the rendered document's `.get("prune")` leaf axis to
15881///     pin the substrate's canonical `true` seed (the
15882///     [`cluster_bundle_kustomization_prune_pins_lifted_true`] per-CR
15883///     production-emit pin).
15884///
15885/// Both the production emit site + the one test-fixture navigation site
15886/// name the same Flux v2 per-CR garbage-collection-toggle leaf-scalar-
15887/// key and must move together on any hypothetical Flux v3 rename
15888/// (upstream Flux v3 roadmap floats candidates like `garbageCollect` /
15889/// `sweep` / `pruneOrphaned` / `deleteOrphans` in the migration prose).
15890/// Until this lift landed the axis carried an inline `prune` literal at
15891/// the one production emit site (caixa-flux/src/lib.rs — the
15892/// `prune: true` leaf inside the `cluster_bundle` `kustomization.yaml`
15893/// format-string template's top-level `spec` position) — the sole
15894/// occurrence of the same load-bearing Flux-v2-per-CR-garbage-
15895/// collection-toggle-leaf-scalar-key convention, drift-prone by
15896/// construction ahead of the second occurrence the M4
15897/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
15898/// `Kustomization` synthesis will surface, where a per-renderer local
15899/// `pub const FLUX_KUSTOMIZATION_KEY_PRUNE: &str = "…"` (the canonical
15900/// drift footgun where a sibling local `pub const` could happen to
15901/// carry the same string at the source while pointing at a different
15902/// `&'static` allocation) would let the two renderers silently disagree
15903/// on the substrate's canonical sweep-what-you-removed semantic.
15904///
15905/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
15906/// "every recurring shape becomes a generator before it becomes a
15907/// pattern; every pattern becomes a library before it becomes
15908/// duplicated code. The duplication budget is zero.") promotes the
15909/// constant to a typed substrate-side `&'static str` in advance of the
15910/// second occurrence the M4 materializer will surface — so the second
15911/// consumer inherits the canonical per-CR garbage-collection-toggle
15912/// leaf-scalar-key by construction without opportunity for per-renderer
15913/// drift.
15914///
15915/// Same "the typed constant lives in one place" discipline the sibling
15916/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) install-path-only
15917/// per-CR namespace-seeder-toggle leaf-scalar-key +
15918/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7) upgrade-
15919/// path-only per-CR remediation-toggle leaf-scalar-key +
15920/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key +
15921/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key
15922/// + [`FLUX_HELMRELEASE_KEY_INSTALL`] / [`FLUX_HELMRELEASE_KEY_UPGRADE`]
15923/// (7767c26) parent-container-axis-key pair +
15924/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15925/// value halves of the per-path per-CR HelmRelease spec surface
15926/// established — extends the discipline from the co-resident per-caixa
15927/// `HelmRelease` CR spec surface onto the co-resident per-caixa
15928/// `Kustomization` CR spec surface at the mirror-symmetric top-level
15929/// `spec.prune` position.
15930///
15931/// [cf]: ../../caixa_flux/index.html
15932/// [kust]: https://fluxcd.io/flux/components/kustomize/kustomizations/
15933pub const FLUX_KUSTOMIZATION_KEY_PRUNE: &str = "prune";
15934
15935/// Canonical Flux v2 `Kustomization.spec.prune` per-CR garbage-collection-
15936/// toggle scalar-value default the substrate seeds into every per-caixa
15937/// `kustomization.yaml` document at the paired
15938/// [`FLUX_KUSTOMIZATION_KEY_PRUNE`] leaf-scalar-key axis. Pairs with the
15939/// sibling [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917) leaf-scalar-key
15940/// half of the same `(leaf-key, scalar-value)` per-CR garbage-collection-
15941/// toggle declaration pair — the Flux v2 kustomize-controller's per-CR
15942/// reconcile loop reads the scalar under that exact leaf key, so drift
15943/// on either axis is equally load-bearing (a rebrand on this canonical
15944/// scalar-value default that failed to reach every renderer's emit site
15945/// would silently split the substrate's chosen sweep-what-you-removed
15946/// semantic between the operator-facing canonical default and every
15947/// per-caixa `Kustomization` document's per-CR garbage-collection-toggle,
15948/// with no field naming the semantic-drift root cause far from the
15949/// source `caixa.lisp` / the renderer's format-string template).
15950///
15951/// The `true` seed opts every emitted per-caixa `Kustomization` into
15952/// the substrate's canonical GitOps-side sweep-what-you-removed
15953/// semantic: on every reconcile the kustomize-controller garbage-
15954/// collects any per-caixa resource the source manifest set previously
15955/// reconciled but no longer carries, converging the cluster's per-
15956/// caixa live state to the caixa's tatara-lisp source-of-truth
15957/// verbatim. A future substrate-side rebrand to `false` (or a per-
15958/// cluster override the operator pins for a class of clusters where a
15959/// human is expected to prune orphaned resources by hand, or a
15960/// per-caixa opt-out slot the ABSORPTION-ROADMAP.md M4 typed-slot
15961/// trajectory adds once the substrate grows a `:kustomization :prune`
15962/// author-side toggle) is a one-line edit on this canonical declaration,
15963/// not a coordinated rewrite across every future per-target renderer
15964/// the substrate adds. Peer with the sibling
15965/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
15966/// value default on the peer canonical-Flux-v2-per-CR-substrate-
15967/// default surface — the retry-cap default names the per-path per-CR
15968/// remediation retry ceiling, and this garbage-collection-toggle
15969/// default names whether the per-CR reconcile loop sweeps orphaned
15970/// resources at all. Both are substrate-side policy choices the
15971/// operator inherits when the per-caixa [`ClusterBundleOpts`][co]
15972/// doesn't pin an override.
15973///
15974/// The single source of truth every rendered Flux bundle axis that
15975/// names the per-CR garbage-collection-toggle scalar reaches for:
15976///
15977///   - the rendered `kustomization.yaml` document's `spec.prune`
15978///     scalar-value axis (caixa-flux/src/lib.rs — the [`cluster_bundle`][cb]
15979///     `kustomization.yaml` format-string template's per-CR garbage-
15980///     collection-toggle scalar under the top-level `spec` position,
15981///     threading the same `bool` through a `{prune_default}` named-arg
15982///     interpolation);
15983///   - the one test-fixture navigation site in caixa-flux's `mod tests`
15984///     that probes the rendered document's `.get("prune")` scalar axis
15985///     to pin the substrate's canonical `true` seed against the lifted
15986///     default (the
15987///     [`cluster_bundle_kustomization_prune_pins_lifted_true`] per-CR
15988///     production-emit pin).
15989///
15990/// Both the production emit site + the one test-fixture navigation site
15991/// now consume the same `bool` at emit time through the sibling
15992/// re-export [`caixa_flux::FLUX_KUSTOMIZATION_PRUNE_DEFAULT`][cf], so a
15993/// future substrate-side toggle migration on the canonical scalar-value
15994/// axis reaches every consumer through one `bool` by construction —
15995/// with no opportunity for per-renderer drift where a rebrand on one
15996/// axis without a coordinated edit on the other would silently disagree
15997/// on the sweep-what-you-removed semantic. Until this lift landed the
15998/// axis carried an inline `true` scalar-value literal at the sole
15999/// production-code call site (the `prune: true` leaf inside the
16000/// [`cluster_bundle`][cb] `kustomization.yaml` format-string template's
16001/// top-level `spec` position) plus the sibling test-fixture navigation
16002/// site — two occurrences of the same load-bearing Flux-v2-per-CR-
16003/// garbage-collection-toggle-scalar-value convention, drift-prone by
16004/// construction ahead of the third occurrence the M4
16005/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
16006/// `Kustomization` synthesis will surface, where a per-renderer local
16007/// `pub const FLUX_KUSTOMIZATION_PRUNE_DEFAULT: bool = …` at any
16008/// downstream renderer would let the two consumers silently disagree
16009/// on the substrate's canonical seed.
16010///
16011/// Same "the typed constant lives in one place" discipline the
16012/// [`DEFAULT_NAMESPACE`] (a085b26) / [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
16013/// (7197d38) / [`DEFAULT_LIBRARY_NAME`] (41438dc) /
16014/// [`crate::DEFAULT_SERVICO_PORT`] (1e22add) /
16015/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) /
16016/// [`crate::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) /
16017/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f) /
16018/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) lifts apply
16019/// on the peer canonical-substrate-default-load-bearing-scalar surface.
16020///
16021/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
16022/// [cf]: ../../caixa_flux/index.html
16023/// [co]: ../../caixa_flux/struct.ClusterBundleOpts.html
16024pub const FLUX_KUSTOMIZATION_PRUNE_DEFAULT: bool = true;
16025
16026/// Canonical substrate-side default for the
16027/// `HelmRelease.spec.values.<library>.enabled` scalar-value toggle every
16028/// [`caixa_flux::cluster_bundle`][cb]-emitted `helmrelease.yaml` document
16029/// seeds inside its per-caixa values overlay to force-on the paired
16030/// [`DEFAULT_LIBRARY_NAME`] child chart at the per-cluster
16031/// `HelmRelease`-side apply step. Pairs with the sibling
16032/// [`HELM_VALUES_KEY_ENABLED`] leaf-scalar-key half of the
16033/// `(leaf-key, scalar-value)` per-values-overlay child-chart
16034/// enablement-toggle declaration pair — the key half names the
16035/// canonical `values.<library>.enabled` leaf-scalar-key axis every
16036/// consumer (`caixa-helm`'s `values.yaml` per-chart default, this
16037/// crate's `cluster_bundle` overlay) probes on, and this scalar-value
16038/// half names the substrate-side default the `cluster_bundle` overlay
16039/// path seeds under it. Semantically distinct from — and inverse of —
16040/// the `RenderOpts::enabled_default = false` default that
16041/// [`caixa_helm::RenderOpts::default`] seeds for the standalone
16042/// `lareira-<nome>` chart's own `values.yaml` (that path renders
16043/// `enabled: false` so cluster operators must opt each caixa in
16044/// per-cluster); the `cluster_bundle` composition path is the
16045/// substrate-side opt-in path where the operator has already asserted
16046/// per-caixa cluster-scoped ownership by materializing a per-caixa
16047/// `GitRepository` + `HelmRelease` + `Kustomization` trio, so the overlay
16048/// forces the child chart on by seeding `enabled: true` under the
16049/// `values.<library>` wrap.
16050///
16051/// Rendered to canonical YAML `true` verbatim. A future substrate-side
16052/// rebrand to `false` (or the M4 typed-slot trajectory adding a per-caixa
16053/// `:cluster-bundle :enabled` author-side toggle the operator flips per
16054/// caixa) is a one-line edit on this canonical declaration, not a
16055/// coordinated rewrite across the sole production emit site + its
16056/// paired test-fixture navigation site. Peer with the sibling
16057/// [`FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`] (be1904b),
16058/// [`FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`] (be1904b),
16059/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae), and
16060/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) scalar-value defaults
16061/// on the peer canonical-Flux-v2-per-CR-substrate-default surface — the
16062/// four sibling scalar-value defaults name per-CR toggle-shape axes at
16063/// the `HelmRelease.spec.install.*` / `HelmRelease.spec.upgrade.*` /
16064/// `HelmRelease.spec.upgrade.remediation.retries` /
16065/// `Kustomization.spec.prune` sub-block positions, and this
16066/// scalar-value default names the child-chart-enablement toggle at the
16067/// deeper `HelmRelease.spec.values.<library>.enabled` values-overlay
16068/// position — all five are substrate-side policy choices the operator
16069/// inherits when the per-caixa [`ClusterBundleOpts`][co] doesn't pin an
16070/// override.
16071///
16072/// The single source of truth every rendered Flux bundle axis that
16073/// names the per-CR values-overlay child-chart-enablement-toggle
16074/// scalar reaches for:
16075///
16076///   - the rendered `helmrelease.yaml` document's
16077///     `spec.values.<library>.enabled` scalar-value axis
16078///     (caixa-flux/src/lib.rs — the [`cluster_bundle`][cb]
16079///     `helmrelease.yaml` format-string template's per-CR values-overlay
16080///     child-chart-enablement-toggle scalar under the per-`{library_name}`
16081///     wrap position, threading the same `bool` through a
16082///     `{lareira_enabled_default}` named-arg interpolation);
16083///   - the one test-fixture navigation site in caixa-flux's `mod tests`
16084///     that probes the rendered document's
16085///     `values.<library>.enabled` scalar axis to pin the substrate's
16086///     canonical `true` seed against the lifted default (the
16087///     `cluster_bundle_helmrelease_wrap_key_pins_canonical_pleme_computeunit_string`
16088///     per-CR production-emit pin's `Some(true)` assertion).
16089///
16090/// Both the production emit site + the test-fixture navigation site now
16091/// consume the same `bool` at emit time through the sibling re-export
16092/// [`caixa_flux::CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`][cf], so a
16093/// future substrate-side toggle migration reaches every consumer through
16094/// one `bool` by construction — with no opportunity for per-renderer
16095/// drift where a rebrand on one axis without a coordinated edit on the
16096/// other would silently disagree on the substrate's chosen child-chart
16097/// force-on-under-composition semantic. Until this lift landed the
16098/// axis carried an inline `true` scalar-value literal at the sole
16099/// production-code call site (the `{enabled_key}: true` leaf inside the
16100/// [`cluster_bundle`][cb] `helmrelease.yaml` format-string template's
16101/// per-`{library_name}` wrap position) plus the test-fixture
16102/// navigation-site `Some(true)` assertion — two occurrences of the same
16103/// load-bearing values-overlay child-chart-enablement-toggle-scalar-value
16104/// convention, drift-prone by construction ahead of the third occurrence
16105/// the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
16106/// per-Aplicacao `HelmRelease` synthesis will surface.
16107///
16108/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
16109/// [cf]: ../../caixa_flux/index.html
16110/// [co]: ../../caixa_flux/struct.ClusterBundleOpts.html
16111pub const CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT: bool = true;
16112
16113/// Canonical substrate-side default for the
16114/// `values.<library>.enabled` scalar-value toggle every
16115/// [`caixa_helm::render_chart_for_servico`][cs]-emitted standalone
16116/// `lareira-<nome>` chart's `values.yaml` document seeds inside its per-caixa
16117/// [`DEFAULT_LIBRARY_NAME`] wrap block to leave the paired
16118/// [`DEFAULT_LIBRARY_NAME`] child chart opted-out at the per-cluster
16119/// `helm template` / `helm install` apply step. Pairs with the sibling
16120/// [`HELM_VALUES_KEY_ENABLED`] leaf-scalar-key half of the
16121/// `(leaf-key, scalar-value)` per-values-block child-chart-enablement-toggle
16122/// declaration pair — the key half names the canonical
16123/// `values.<library>.enabled` leaf-scalar-key axis every consumer (this
16124/// standalone-path default, [`caixa_flux::cluster_bundle`][cb]'s per-CR
16125/// values-overlay) probes on, and this scalar-value half names the
16126/// substrate-side default the standalone per-chart path seeds under it.
16127/// Semantically distinct from — and inverse of — the peer
16128/// [`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`] default that
16129/// [`caixa_flux::cluster_bundle`][cb]'s `helmrelease.yaml` values overlay
16130/// seeds for the substrate-side composition-path force-on (that path
16131/// renders `enabled: true` in the per-cluster `HelmRelease.spec.values.<library>`
16132/// overlay so the operator's per-caixa cluster-scoped ownership at bundle
16133/// materialization time carries a force-on for the child chart); the
16134/// standalone per-chart path is the substrate-side opt-out path where the
16135/// operator has not yet asserted per-caixa cluster-scoped ownership by
16136/// materializing a per-caixa `GitRepository` + `HelmRelease` +
16137/// `Kustomization` trio, so the per-chart `values.yaml` seeds
16138/// `enabled: false` under the `values.<library>` wrap and cluster operators
16139/// must opt each caixa in per-cluster.
16140///
16141/// Rendered to canonical YAML `false` verbatim. A future substrate-side
16142/// rebrand to `true` (or the M4 typed-slot trajectory adding a per-caixa
16143/// `:standalone :enabled` author-side toggle the author flips per caixa) is
16144/// a one-line edit on this canonical declaration, not a coordinated rewrite
16145/// across the sole production emit site + its paired test-fixture
16146/// navigation sites. Peer with the sibling
16147/// [`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`] scalar-value default on the
16148/// peer canonical-Helm-per-values-block-substrate-default surface — the two
16149/// sibling scalar-value defaults name mirror-symmetric per-path
16150/// child-chart-enablement-toggle-scalar-value defaults at the exact same
16151/// `values.<library>.enabled` sub-block position on the standalone
16152/// per-chart-`values.yaml` path (this const) and the composition
16153/// per-cluster-`HelmRelease` values-overlay path
16154/// ([`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`]) — both are substrate-side
16155/// policy choices the operator inherits when the per-caixa
16156/// [`caixa_helm::RenderOpts`][cro] / [`caixa_flux::ClusterBundleOpts`][co]
16157/// doesn't pin an override.
16158///
16159/// The single source of truth every rendered `values.yaml` axis that
16160/// names the per-values-block child-chart-enablement-toggle scalar on the
16161/// standalone per-chart path reaches for:
16162///
16163///   - the rendered `values.yaml` document's
16164///     `<library>.enabled` scalar-value axis
16165///     (caixa-helm/src/lib.rs — the [`caixa_helm::build_values_yaml`][cbv]
16166///     `serde_yaml::Value::Bool(opts.enabled_default)` block-insertion
16167///     under the per-`{library_name}` wrap position, threading the same
16168///     `bool` through the [`caixa_helm::RenderOpts::enabled_default`][cro]
16169///     default-knob);
16170///   - the [`caixa_helm::RenderOpts::default()`][cro] impl-body
16171///     `enabled_default: STANDALONE_LAREIRA_ENABLED_DEFAULT` field seed
16172///     the standalone per-chart path threads into every per-caixa
16173///     `render_chart_for_servico` call site.
16174///
16175/// Both the production emit site + the default-knob seed now consume the
16176/// same `bool` at emit time through the sibling re-export
16177/// [`caixa_helm::STANDALONE_LAREIRA_ENABLED_DEFAULT`][ch], so a future
16178/// substrate-side toggle migration reaches every consumer through one
16179/// `bool` by construction — with no opportunity for per-renderer drift
16180/// where a rebrand on one axis without a coordinated edit on the other
16181/// would silently disagree on the substrate's chosen
16182/// standalone-per-chart-path opt-out semantic. Until this lift landed
16183/// the axis carried an inline `enabled_default: false` scalar-value
16184/// literal at the sole production-code call site (the
16185/// [`caixa_helm::RenderOpts::default()`][cro] impl-body field seed at
16186/// `caixa-helm/src/lib.rs:700`) — one occurrence of the same
16187/// load-bearing per-values-block child-chart-enablement-toggle-scalar-value
16188/// convention as the peer [`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`] on the
16189/// composition path, drift-prone by construction ahead of the M4
16190/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
16191/// per-Servico standalone-chart synthesis surfacing the third occurrence.
16192///
16193/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
16194/// [cs]: ../../caixa_helm/fn.render_chart_for_servico.html
16195/// [cbv]: ../../caixa_helm/fn.build_values_yaml.html
16196/// [ch]: ../../caixa_helm/index.html
16197/// [cro]: ../../caixa_helm/struct.RenderOpts.html
16198/// [co]: ../../caixa_flux/struct.ClusterBundleOpts.html
16199pub const STANDALONE_LAREIRA_ENABLED_DEFAULT: bool = false;
16200
16201/// Canonical Flux v2 `Kustomization.spec.path` per-CR source-sub-tree
16202/// leaf-scalar-key every `caixa-flux`-emitted `kustomization.yaml`
16203/// document seeds under its top-level `spec` position to name the sub-
16204/// tree of the paired [`FLUX_GITREPOSITORY_YAML_FILENAME`] GitRepository
16205/// the Flux v2 kustomize-controller-side per-CR reconcile loop pulls
16206/// the desired-state manifest set from at reconcile time. Drift on this
16207/// leaf silently unbinds every per-caixa `Kustomization` from its
16208/// paired per-caixa sub-tree of the pleme-io k8s repository — the
16209/// kustomize-controller then either reconciles the whole GitRepository
16210/// root (when the CR omits the leaf, the controller defaults to `./`,
16211/// pulling every unrelated cluster's manifests through the wrong
16212/// per-caixa `Kustomization`) or refuses to reconcile at all (when the
16213/// leaf points at a path the GitRepository doesn't carry, the CR sits
16214/// perpetually at `BuildFailed` naming the missing sub-tree far from
16215/// the source `caixa.lisp` / the renderer's format-string template).
16216///
16217/// Distinct from the sibling K8s-Gateway-API-side [`GATEWAY_API_KEY_PATH`]
16218/// (9f45aa4) per-`HTTPRouteMatch` path-matcher container-axis key and
16219/// the sibling Cilium-CNP-side [`CILIUM_KEY_PATH`] (bec2ce9) per-
16220/// `toPorts[].rules.http[]` URL-path predicate leaf-scalar-key: all
16221/// three constants spell the same underlying `"path"` string but name
16222/// distinct schema axes on distinct CRD groups — the Flux-side axis is a
16223/// per-`Kustomization`-CR source-sub-tree leaf scalar on the Flux v2
16224/// `kustomize.toolkit.fluxcd.io/v1` `Kustomization` CRD's `spec.path`
16225/// entry, the Gateway-API-side axis is a per-`HTTPRouteMatch` path-
16226/// matcher two-leaf container (`{type, value}`) on the K8s Gateway API
16227/// v1 `HTTPRoute` CRD's `spec.rules[].matches[]` entry, the Cilium-side
16228/// axis is a per-HTTP-rule URL-path predicate leaf scalar on the Cilium
16229/// `cilium.io/v2` `CiliumNetworkPolicy` CRD's per-`toPorts[].rules.http[]`
16230/// entry. Keeping them as sibling `pub const` declarations (rather than
16231/// coalescing onto a single shared constant that happens to carry the
16232/// same string) mirrors the deliberate axis-independence discipline the
16233/// sibling [`CILIUM_KEY_PATH`] / [`GATEWAY_API_KEY_PATH`] pair already
16234/// codifies on the sibling per-CRD-group axes, so a future Flux v3 per-
16235/// `Kustomization`-CR source-sub-tree leaf-key rebrand (candidates like
16236/// `sourcePath` / `manifestsPath` / `sourceRoot` upstream Flux v3
16237/// roadmap floats in the migration prose) can land independently of
16238/// any Cilium-side or Gateway-API-side per-CRD-schema rebrand without
16239/// any cross-CRD coordination footgun where a shared constant would
16240/// force a coupled edit against schema evolutions the three CRD
16241/// projects run on independent cadences. Note: Rust's `&'static str`
16242/// interner coalesces identical byte-sequences onto one storage
16243/// allocation at codegen time, so at runtime a `.as_ptr()` comparison
16244/// across the trio can't distinguish "sibling `pub const` declarations
16245/// carrying identical bytes" from "coalesced canonical declaration" —
16246/// the axis-independence discipline lives at the rustc symbol-name
16247/// axis (the three `pub const CILIUM_KEY_PATH` / `pub const
16248/// GATEWAY_API_KEY_PATH` / `pub const FLUX_KUSTOMIZATION_KEY_PATH`
16249/// symbols a future rebrand of one leaves the other two structurally
16250/// untouched under) rather than the runtime-address axis, and the
16251/// per-axis re-export identity pins in the consuming renderer crates
16252/// (each pinning the local re-export against its own canonical
16253/// declaration on its own axis) remain the load-bearing "no sibling
16254/// local `pub const` drift" gate for the trio.
16255///
16256/// The single source of truth every rendered Flux bundle axis that
16257/// names the per-`Kustomization`-CR source-sub-tree leaf reaches for:
16258///
16259///   - the rendered `kustomization.yaml` document's `spec.path` leaf-
16260///     scalar-key axis (caixa-flux/src/lib.rs — the [`cluster_bundle`]
16261///     `kustomization.yaml` format-string template's per-CR source-sub-
16262///     tree leaf under the top-level `spec` position, threading the
16263///     same `&'static str` through a new `{path_key}` named-arg
16264///     interpolation);
16265///   - the one test-fixture navigation site in caixa-flux's `mod tests`
16266///     that probes the rendered document's `.get("path")` leaf axis to
16267///     pin the substrate's canonical per-cluster / per-caixa sub-tree
16268///     path seed (the [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`]
16269///     per-CR production-emit pin).
16270///
16271/// Both the production emit site + the one test-fixture navigation
16272/// site name the same Flux v2 per-`Kustomization`-CR source-sub-tree
16273/// leaf-scalar-key and must move together on any hypothetical Flux v3
16274/// rename. Until this lift landed the axis carried an inline `path`
16275/// literal at the one production emit site (caixa-flux/src/lib.rs —
16276/// the `path: ./clusters/{cluster}/services/{name}` leaf inside the
16277/// `cluster_bundle` `kustomization.yaml` format-string template's top-
16278/// level `spec` position) — the sole occurrence of the same load-
16279/// bearing Flux-v2-per-`Kustomization`-CR-source-sub-tree-leaf-scalar-
16280/// key convention, drift-prone by construction ahead of the second
16281/// occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
16282/// materializer's per-Aplicacao `Kustomization` synthesis will
16283/// surface, where a per-renderer local
16284/// `pub const FLUX_KUSTOMIZATION_KEY_PATH: &str = "…"` (the canonical
16285/// drift footgun where a sibling local `pub const` could happen to
16286/// carry the same string at the source while pointing at a different
16287/// `&'static` allocation) would let the two renderers silently
16288/// disagree on the substrate's canonical per-`Kustomization`-CR
16289/// source-sub-tree leaf-scalar-key convention.
16290///
16291/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5) lifts
16292/// the constant in advance of the second occurrence the M4 materializer
16293/// will surface — so the second consumer inherits the canonical per-CR
16294/// source-sub-tree leaf-scalar-key by construction without opportunity
16295/// for per-renderer drift. Same "the typed constant lives in one place"
16296/// discipline the sibling [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917)
16297/// per-CR garbage-collection-toggle leaf-scalar-key lift on the same
16298/// per-`Kustomization`-CR spec surface established — extends the
16299/// discipline from the co-resident per-`Kustomization`-CR `spec.prune`
16300/// top-level per-CR-toggle leaf-scalar-key onto the co-resident per-
16301/// `Kustomization`-CR `spec.path` top-level per-CR-source-sub-tree
16302/// leaf-scalar-key at the mirror-symmetric top-level `spec` position.
16303///
16304/// [cf]: ../../caixa_flux/index.html
16305/// [kust]: https://fluxcd.io/flux/components/kustomize/kustomizations/
16306pub const FLUX_KUSTOMIZATION_KEY_PATH: &str = "path";
16307
16308/// Canonical substrate-side per-cluster / per-caixa `Kustomization.spec.path`
16309/// source-sub-tree scalar composer — the `./clusters/<cluster>/services/<nome>`
16310/// GitRepository-relative directory-tree seed every `caixa-flux`-emitted
16311/// `kustomization.yaml` document mounts under its lifted
16312/// [`FLUX_KUSTOMIZATION_KEY_PATH`] leaf-scalar-key at the top-level `spec`
16313/// position so the Flux v2 kustomize-controller's per-CR reconcile loop
16314/// walks into the paired per-cluster / per-caixa sub-tree of the pleme-io
16315/// k8s repository (rather than the `GitRepository` root, which would pull
16316/// every unrelated cluster's manifests through the wrong per-caixa
16317/// `Kustomization`).
16318///
16319/// The rendered string is the substrate's contract with the pleme-io k8s
16320/// repository's canonical directory-tree layout: every per-caixa Servico's
16321/// rendered manifests live at `pleme-io/k8s/clusters/<cluster>/services/<nome>/`,
16322/// so the Flux v2 kustomize-controller-side per-CR reconcile loop keys off
16323/// the same GitRepository-relative sub-tree seed by construction — the
16324/// composer output is the exact `spec.path` scalar the substrate seeds into
16325/// every emitted per-caixa `kustomization.yaml` document under its top-
16326/// level `spec` position.
16327///
16328/// Composes two axes:
16329///
16330///   - the per-cluster prefix — the `./clusters/<cluster>/` half of the
16331///     sub-tree seed that scopes the emit to the paired cluster's
16332///     manifest set (so two clusters hosting the same per-caixa Servico —
16333///     `rio` vs `paris` — land at distinct `spec.path` scalars with no
16334///     cross-cluster reconcile drift at the kustomize-controller's per-CR
16335///     apply loop);
16336///   - the per-caixa suffix — the `/services/<nome>` half of the sub-tree
16337///     seed that scopes the emit to the paired per-caixa Servico's
16338///     manifest sub-directory under the cluster's `services/` directory
16339///     (so two per-caixa Servicos co-resident under the same cluster —
16340///     `hello-rio` vs `cart` — land at distinct `spec.path` scalars with
16341///     no per-caixa reconcile drift at the same kustomize-controller
16342///     apply loop).
16343///
16344/// Peer to [`cilium_network_policy_name`] / [`gateway_api_http_route_name`]
16345/// / [`oci_chart_ref`] / [`lareira_chart_name`] on the sibling substrate-
16346/// side canonical-composer-of-a-canonical-scalar-that-consumers-key-off
16347/// axis: every writer-side helper composes a canonical load-bearing
16348/// scalar the substrate contracts with a downstream consumer's index
16349/// (Cilium's per-CNP `metadata.name`, Gateway API's per-HTTPRoute
16350/// `metadata.name`, Helm's OCI-artifact ref, Helm's Chart.yaml `name:`
16351/// axis). This composer's `Kustomization.spec.path` peer names the Flux
16352/// v2 kustomize-controller-side per-CR reconcile-target sub-tree index —
16353/// same "the load-bearing multi-axis composition lives in one place"
16354/// discipline extended from the mesh renderer's per-CR-identity-scalar
16355/// axes onto the flux renderer's per-CR-source-sub-tree axis.
16356///
16357/// Until this lift landed the two-axis composition sat as a verbatim
16358/// inline `format!("./clusters/{cluster}/services/{name}")` template at
16359/// the sole `cluster_bundle` `kustomization.yaml` format-string
16360/// production emit site plus a mirror-symmetric verbatim inline
16361/// `format!("./clusters/{cluster}/services/{name}", …)` at the paired
16362/// `cluster_bundle_kustomization_path_pins_lifted_sub_tree` test-fixture
16363/// navigation site — the substrate's canonical per-cluster / per-caixa
16364/// sub-tree seed had no compile-time link between the two sites. A
16365/// future substrate-side directory-tree axis rebrand (`clusters/` →
16366/// `environments/` for a multi-env-per-cluster axis extension, `services/`
16367/// → `servicos/` for a portuguese-canonical directory-name migration
16368/// matching the sibling `:servicos` slot spelling, a per-tenant scoping
16369/// prefix for multi-tenant Aplicacao hosting) would have had to be
16370/// threaded through both sites in lockstep or the two would silently
16371/// split: the production emit would key off the drifted encoding while
16372/// the test pin still asserts the original. Lifting closes the drift
16373/// footgun ahead of the second production-emit occurrence the M4
16374/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
16375/// `Kustomization` synthesis will surface — the second consumer inherits
16376/// the canonical per-cluster / per-caixa sub-tree composition by
16377/// construction without opportunity for per-renderer drift.
16378///
16379/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5) lifts
16380/// the composition in advance of the second occurrence the M4 materializer
16381/// will surface, so the second consumer inherits the canonical sub-tree
16382/// seed by construction.
16383#[must_use]
16384pub fn flux_kustomization_source_subtree(cluster: &str, nome: &str) -> String {
16385    format!("./clusters/{cluster}/services/{nome}")
16386}
16387
16388/// Canonical Flux v2 `Kustomization.spec.timeout` per-CR reconcile wall-
16389/// clock cap leaf-scalar-key every `caixa-flux`-emitted
16390/// `kustomization.yaml` document seeds under its top-level `spec`
16391/// position to name the ceiling on how long the Flux v2 kustomize-
16392/// controller-side per-CR reconcile loop is allowed to spend applying
16393/// the paired [`FLUX_KUSTOMIZATION_KEY_PATH`]-scoped sub-tree of the
16394/// paired [`FLUX_GITREPOSITORY_YAML_FILENAME`] GitRepository before it
16395/// marks the `Kustomization` `Ready: False` and stops retrying — the
16396/// substrate's canonical "how long we let a per-caixa manifest-set
16397/// reconcile run before Flux gives up" contract with the kustomize-
16398/// controller's per-CR reconcile loop. Drift on this leaf silently
16399/// strips the substrate's chosen reconcile-ceiling from every emitted
16400/// per-caixa `Kustomization` document — the kustomize-controller then
16401/// falls back to the upstream Flux v2 controller-side default cap
16402/// (which the upstream project ships at a value tuned for the average
16403/// upstream Flux-managed manifest set, not the substrate's per-caixa
16404/// idempotency-checkpoint cadence the sibling
16405/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] retry-ceiling and
16406/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] reconcile-poll cadence are
16407/// jointly tuned against), letting a persistently-failing per-caixa
16408/// manifest apply consume kustomize-controller reconcile-loop cycles
16409/// past the substrate's chosen ceiling with no field naming the
16410/// timeout-drift root cause.
16411///
16412/// The single source of truth every rendered Flux bundle axis that
16413/// names the per-`Kustomization`-CR reconcile wall-clock cap leaf
16414/// reaches for:
16415///
16416///   - the rendered `kustomization.yaml` document's `spec.timeout`
16417///     leaf-scalar-key axis (caixa-flux/src/lib.rs — the
16418///     [`cluster_bundle`] `kustomization.yaml` format-string template's
16419///     per-CR reconcile wall-clock cap leaf under the top-level `spec`
16420///     position, threading the same `&'static str` through a new
16421///     `{timeout_key}` named-arg interpolation);
16422///   - the one test-fixture navigation site in caixa-flux's `mod tests`
16423///     that probes the rendered document's `.get("timeout")` leaf axis
16424///     to pin the substrate's canonical wall-clock cap seed.
16425///
16426/// Both the production emit site + the one test-fixture navigation
16427/// site name the same Flux v2 per-`Kustomization`-CR reconcile wall-
16428/// clock cap leaf-scalar-key and must move together on any
16429/// hypothetical Flux v3 rename. Until this lift landed the axis
16430/// carried an inline `timeout` literal at the one production emit site
16431/// (caixa-flux/src/lib.rs — the `timeout: 5m` leaf inside the
16432/// `cluster_bundle` `kustomization.yaml` format-string template's top-
16433/// level `spec` position) — the sole occurrence of the same load-
16434/// bearing Flux-v2-per-`Kustomization`-CR-reconcile-wall-clock-cap-
16435/// leaf-scalar-key convention, drift-prone by construction ahead of
16436/// the second occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
16437/// materializer's per-Aplicacao `Kustomization` synthesis will
16438/// surface, where a per-renderer local
16439/// `pub const FLUX_KUSTOMIZATION_KEY_TIMEOUT: &str = "…"` (the
16440/// canonical drift footgun where a sibling local `pub const` could
16441/// happen to carry the same string at the source while pointing at a
16442/// different `&'static` allocation) would let the two renderers
16443/// silently disagree on the substrate's canonical reconcile-ceiling-
16444/// declaration leaf-scalar-key convention.
16445///
16446/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5)
16447/// lifts the constant in advance of the second occurrence the M4
16448/// materializer will surface — so the second consumer inherits the
16449/// canonical per-CR reconcile wall-clock cap leaf-scalar-key by
16450/// construction without opportunity for per-renderer drift. Pairs
16451/// with the sibling [`DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] scalar-
16452/// value half of the same `(leaf-key, scalar-value)` per-path
16453/// reconcile-ceiling-declaration pair — extends the drift-closing
16454/// discipline the scalar-value lift established from the value the
16455/// leaf holds onto the leaf-key itself. Same shape as the sibling
16456/// [`FLUX_KUSTOMIZATION_KEY_PATH`] (613d7ed) per-CR source-sub-tree
16457/// leaf-scalar-key + [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917) per-CR
16458/// garbage-collection-toggle leaf-scalar-key lifts on the co-resident
16459/// per-`Kustomization`-CR spec surface — extends the discipline from
16460/// the co-resident per-`Kustomization`-CR `spec.path` source-sub-tree
16461/// leaf-scalar-key and per-`Kustomization`-CR `spec.prune` garbage-
16462/// collection-toggle leaf-scalar-key onto the co-resident per-
16463/// `Kustomization`-CR `spec.timeout` reconcile wall-clock cap leaf-
16464/// scalar-key at the mirror-symmetric top-level `spec` position.
16465///
16466/// [cf]: ../../caixa_flux/index.html
16467/// [kust]: https://fluxcd.io/flux/components/kustomize/kustomizations/
16468pub const FLUX_KUSTOMIZATION_KEY_TIMEOUT: &str = "timeout";
16469
16470/// Canonical Flux v2 `Kustomization.spec.timeout` per-CR reconcile
16471/// wall-clock cap default the substrate seeds into every per-caixa
16472/// `kustomization.yaml` document. Every rendered per-caixa Flux v2
16473/// `Kustomization` CR consults the same `&'static str` at emit time so
16474/// a future substrate-side reconcile-ceiling migration (`"5m"` → `"3m"`
16475/// on faster per-caixa idempotency-checkpoint cadence once the sibling
16476/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] retry-ceiling
16477/// tightens, `"5m"` → `"10m"` on larger per-caixa manifest sets where
16478/// the upstream Flux v2 kustomize-controller-side per-CR reconcile
16479/// duration outgrows the substrate's default ceiling — coordinated
16480/// with the sibling [`DEFAULT_FLUX_RECONCILE_INTERVAL`] reconcile-poll
16481/// cadence tuning cycle) is a one-line edit on this canonical
16482/// declaration, not a coordinated rewrite across the
16483/// [`cluster_bundle`] `kustomization.yaml` template + every future
16484/// per-target renderer the substrate adds.
16485///
16486/// The single source of truth the rendered per-caixa Flux v2 cluster
16487/// bundle's per-`Kustomization`-CR reconcile wall-clock cap default
16488/// seed reaches for:
16489///
16490///   - the rendered `kustomization.yaml` document's `spec.timeout`
16491///     scalar-value axis (caixa-flux/src/lib.rs — the
16492///     [`cluster_bundle`] `kustomization.yaml` format-string template's
16493///     per-CR reconcile wall-clock cap leaf under the top-level `spec`
16494///     position, threading the same `&'static str` through a new
16495///     `{timeout_default}` named-arg interpolation on the leaf keyed
16496///     by the sibling [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`]).
16497///
16498/// The value is a valid Flux v2 reconcile wall-clock cap duration
16499/// scalar (per the upstream Flux v2
16500/// `kustomize.toolkit.fluxcd.io/v1/Kustomization.spec.timeout`
16501/// `metav1.Duration` OpenAPI schema): a non-empty Go-duration-format
16502/// string (e.g. `"5m"`, `"3m"`, `"1h30m"`), which the Flux v2
16503/// controller-side per-CR admission gate parses via
16504/// `metav1.ParseDuration` before installing the per-CR watch. A future
16505/// rebrand on this lift cannot silently land a value the Flux v2
16506/// controller-side admission gate rejects at the *first* per-caixa
16507/// `Kustomization` apply against a cluster, far from the rebrand
16508/// commit's source — the pin at the canonical lift documents the Go-
16509/// duration-format grammar contract with the Flux v2 admission gate
16510/// every downstream consumer of the rendered per-CR reconcile-cap
16511/// axis rests on.
16512///
16513/// Pairs with the sibling [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`] per-Flux-
16514/// v2-`Kustomization`-CR reconcile wall-clock cap scalar-axis key the
16515/// value the substrate seeds here nests directly under across every
16516/// rendered per-caixa Flux v2 `Kustomization` CR — the key half of
16517/// the per-CR `spec.timeout` scalar-key/scalar-value pair lives at
16518/// [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`], the value half's substrate-side
16519/// default seed lives here. Same "the typed constant lives in one
16520/// place" discipline the [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f)
16521/// / [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) /
16522/// [`DEFAULT_APLICACAO_INSTALL_TIMEOUT`](caixa_tatara::DEFAULT_APLICACAO_INSTALL_TIMEOUT)
16523/// (813343f) lifts apply on the peer canonical-substrate-default-
16524/// load-bearing-scalar surface — extends the canonical-substrate-
16525/// default single-sourcing discipline from the peer per-Flux-v2-CR-
16526/// reconcile-poll-cadence / per-HelmRelease-CR-remediation-retry-
16527/// ceiling / per-tatara-Process-install-wall-clock-cap surfaces onto
16528/// the sibling per-Kustomization-CR-reconcile-wall-clock-cap surface
16529/// every rendered per-caixa Flux v2 cluster bundle CR carries.
16530///
16531/// [cf]: ../../caixa_flux/index.html
16532pub const DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT: &str = "5m";
16533
16534/// Canonical K8s Gateway API `GatewayClass` name every `caixa-mesh`-emitted
16535/// [`Gateway`][gw] document declares at its `spec.gatewayClassName` axis —
16536/// the controller-discriminator that binds the emitted `Gateway` to a
16537/// specific `GatewayClass` resource, which in turn names the controller
16538/// (`spec.controllerName`) that reconciles every `HTTPRoute` /
16539/// `GRPCRoute` / `TLSRoute` / `TCPRoute` attached to `Gateway`s bound to
16540/// that class.
16541///
16542/// The single source of truth [`caixa-mesh`][cm]'s `gateway_routes`
16543/// per-`:entrada` `Gateway` emitter (the sole production-code site the
16544/// prior inline `"cilium".into()` literal sat at — the `spec.gatewayClassName`
16545/// field of the emitted `Gateway`'s `spec` block) and every future
16546/// per-target renderer the M3.x + M4 absorption roadmap acknowledges
16547/// (the future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
16548/// `Gateway` synthesis, a future per-cluster / per-edge `Gateway`
16549/// renderer for non-HTTP `:entrada` shapes) consult for the substrate's
16550/// chosen Gateway API controller.
16551///
16552/// The value pins the substrate on the Cilium Gateway API implementation
16553/// — the same eBPF-identity data plane that reconciles every
16554/// [`CILIUM_KIND_NETWORK_POLICY`] the mesh renderer emits alongside the
16555/// `Gateway`. Same-controller Gateway ingress + intra-mesh identity
16556/// policy is the load-bearing "one identity layer, one data plane"
16557/// mesh-composition invariant (MESH-COMPOSITION.md §V — "the `:entrada`
16558/// external ingress and the intra-mesh `:contratos` identity checks
16559/// share an eBPF data plane; a per-caixa split between the ingress
16560/// controller and the identity controller reintroduces the
16561/// two-data-planes drift the mesh composition invariant closes"), so
16562/// splitting the controller across renderers would silently reintroduce
16563/// the exact drift the substrate's mesh composition invariant closes.
16564///
16565/// Until this lift landed the substrate's Gateway API controller choice
16566/// carried an inline `"cilium".into()` literal at the one production-code
16567/// occurrence in caixa-mesh (the `gateway_routes` `Gateway`
16568/// `spec.gatewayClassName` field). The PRIME DIRECTIVE duplication-budget
16569/// rule (THEORY.md §I.3.5, "every recurring shape becomes a generator
16570/// before it becomes a pattern; every pattern becomes a library before it
16571/// becomes duplicated code. The duplication budget is zero.") promotes
16572/// the constant to a typed substrate-side `&'static str` in advance of the
16573/// second occurrence — the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
16574/// materializer's per-Aplicacao `Gateway` synthesis, a future per-cluster
16575/// per-edge `Gateway` renderer, or any per-edition variant the substrate
16576/// forks — so the second consumer inherits the canonical controller
16577/// choice by construction without opportunity for per-renderer drift.
16578///
16579/// A future substrate-side controller migration (the substrate forking
16580/// from Cilium Gateway to Envoy Gateway, Istio Gateway, or any
16581/// per-edition Gateway API v1.x GA controller variant the SIG-Network
16582/// roadmap names) without a coordinated edit on every renderer's inline
16583/// literal would have silently emitted a `Gateway` whose
16584/// `spec.gatewayClassName` referenced a class no controller reconciles —
16585/// apply-side: the `Gateway` sits at `Programmed: False` with no route
16586/// reconciled, every external `:entrada` flow drops at the ingress with
16587/// no field naming the controller-drift root cause. Lifting the value
16588/// here makes the controller-choice axis discipline structural: the
16589/// per-`:entrada` `Gateway` and every future per-Aplicacao materializer
16590/// consult the same `&'static str`, and a future controller migration
16591/// is a one-line edit on the canonical declaration.
16592///
16593/// The value is a valid DNS-1123 label (the K8s apiserver-side floor
16594/// every cluster-scoped `GatewayClass.metadata.name` axis enforces):
16595/// lowercase ASCII alphanumeric with `-` separators, no leading /
16596/// trailing hyphen, length within the [`DNS_1123_LABEL_MAX_LEN`] (63-byte)
16597/// cap. A future rebrand on this lift cannot silently land a value the
16598/// apiserver refuses at the *first* `Gateway` apply against a cluster,
16599/// far from the rebrand commit's source — the typed [`is_dns_1123_label`]
16600/// floor rejects it at caixa-core build time on the canonical lift,
16601/// before any renderer consumes the value. Same "the typed constant
16602/// lives in one place" discipline the [`DEFAULT_NAMESPACE`] (a085b26) /
16603/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) / [`DEFAULT_LIBRARY_NAME`]
16604/// (41438dc) / [`DEFAULT_SERVICO_PORT`] (1e22add) lifts apply on the
16605/// peer canonical-substrate-default-resource-name surface.
16606///
16607/// [gw]: https://gateway-api.sigs.k8s.io/api-types/gateway/
16608/// [cm]: ../../caixa_mesh/index.html
16609pub const DEFAULT_GATEWAY_CLASS_NAME: &str = "cilium";
16610
16611/// Canonical K8s Gateway API `Gateway` per-Gateway controller-binding
16612/// scalar-axis key every `gateway_routes`-emitted `Gateway` document
16613/// mounts its per-Gateway `GatewayClass.metadata.name` reference under
16614/// (`spec.gatewayClassName`). Pairs with the sibling
16615/// [`DEFAULT_GATEWAY_CLASS_NAME`] (d9b0743) — the K8s Gateway API v1 CRD
16616/// schema pins the per-Gateway controller-binding through the scalar
16617/// `spec.gatewayClassName` axis (each `Gateway` names exactly one
16618/// `GatewayClass.metadata.name`; the sibling `spec.listeners[]` +
16619/// `spec.addresses[]` container axes carry the L7-listener fan-out +
16620/// per-Gateway address hint under the same `spec` block), so drift on
16621/// the per-Gateway controller-binding scalar-axis KEY is exactly as
16622/// load-bearing as drift on the sibling `DEFAULT_GATEWAY_CLASS_NAME`
16623/// VALUE the axis wraps (the K8s apiserver-side Gateway API CRD schema
16624/// validator drops any `spec` block whose controller-binding scalar-
16625/// axis carries an unrecognized key — a `"gatewayClass"` /
16626/// `"className"` / `"gatewayClassRef"` typo silently emits a `Gateway`
16627/// whose controller-binding the Gateway API implementation's per-
16628/// Gateway reconcile loop no-ops entirely: no `GatewayClass` is
16629/// resolved, no `controllerName` is looked up, and every external
16630/// `:entrada` flow the Gateway was authored to accept drops at the
16631/// gateway-class-controller's per-Gateway reconcile with no field
16632/// naming the controller-binding-axis-drift root cause).
16633///
16634/// The single source of truth the rendered Aplicacao Gateway-API-side
16635/// ingress bundle's per-Gateway controller-binding-axis-naming reaches
16636/// for:
16637///
16638///   - the rendered `Gateway` document's `spec.gatewayClassName` axis
16639///     (caixa-mesh/src/lib.rs:2016 — the `gateway_routes` per-Aplicacao
16640///     `Gateway`'s `g_spec.insert("gatewayClassName", …)` call).
16641///
16642/// The per-Gateway controller-binding scalar axis names the same
16643/// Gateway-API-implementation-side per-Gateway `GatewayClass`
16644/// resolution axis as the sibling [`DEFAULT_GATEWAY_CLASS_NAME`] VALUE
16645/// it wraps, and must move together on any future Gateway API rebrand
16646/// (an upstream SIG-Network Gateway API v2 rename of the controller-
16647/// binding scalar-axis from `gatewayClassName` to `className` /
16648/// `gatewayClassRef` / `class`, coordinated with the Gateway API
16649/// deprecation cycle). Until this lift landed the KEY axis carried an
16650/// inline `gatewayClassName` literal at the one production-code
16651/// occurrence in caixa-mesh/src/lib.rs:2016 (the `gateway_routes` per-
16652/// Aplicacao Gateway's `g_spec.insert("gatewayClassName", …)` call)
16653/// plus a matching test-fixture navigation inside the in-file
16654/// `gateway_gateway_class_name_uses_lifted_default_gateway_class_name`
16655/// pin's `.get("gatewayClassName")` traversal (caixa-mesh/src/lib.rs:5315)
16656/// — two occurrences of the same load-bearing Gateway-API-CRD-
16657/// `gatewayClassName`-axis-KEY convention, drift-prone by
16658/// construction. A drift on the production site to `"gatewayClass"` /
16659/// `"className"` / `"gatewayClassRef"` would have surfaced as a
16660/// Gateway API implementation-side schema validator drop at apply
16661/// time (the affected `Gateway`'s controller-binding scalar-axis the
16662/// CRD schema validator recognizes as unknown), with every external
16663/// `:entrada` flow the Gateway was authored to accept dropping at the
16664/// gateway-class-controller's per-Gateway reconcile with no field
16665/// naming the controller-binding-drift root cause. A drift on the
16666/// test-fixture side silently masks the emission-side pin
16667/// (`.get("gatewayClassName")` returns `None` under both the drifted-
16668/// key emitter and the drifted-key probe — the downstream
16669/// `.and_then(|c| c.as_str())` chain short-circuits vacuously because
16670/// the outer per-Gateway controller-binding lookup is itself `None`).
16671///
16672/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
16673/// "every recurring shape becomes a generator before it becomes a
16674/// pattern; every pattern becomes a library before it becomes
16675/// duplicated code. The duplication budget is zero.") promotes the
16676/// constant to a typed substrate-side `&'static str` on the same
16677/// trajectory the [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
16678/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
16679/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
16680/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) lifts established on the
16681/// sibling canonical-Gateway-API-body-axis surfaces — completes the
16682/// per-Gateway-body-axis canonical-string-pin set the sibling
16683/// `spec.listeners[]` lift began, closing the (`gatewayClassName`,
16684/// `listeners`) per-`Gateway`-spec-body-axis pair the M3 Aplicacao
16685/// mesh renderer's external `:entrada` ingress contract rests on.
16686/// Together with the peer [`DEFAULT_GATEWAY_CLASS_NAME`] VALUE lift
16687/// (d9b0743) — the `(key, value)` pair-lift discipline the sibling
16688/// `(KUBE_KEY_METADATA, {"name","namespace","labels"})` axis
16689/// established — the per-Gateway controller-binding scalar axis now
16690/// threads both halves of its `(key, value)` typed contract through
16691/// one lifted `&'static str` apiece at the substrate boundary. The
16692/// render-side consumer now threads the same `&'static str` through
16693/// its `g_spec.insert(…)` call so a future Gateway API rebrand on
16694/// the controller-binding scalar axis (or an upstream SIG-Network
16695/// Gateway API v2 rename to a per-CRD sibling name) lands in one
16696/// place; every future renderer that reaches for the canonical
16697/// per-Gateway controller-binding scalar axis (the future M4
16698/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
16699/// `Gateway` fan-out, a future per-cluster `GatewayClass` /
16700/// `ReferenceGrant` renderer whose per-Gateway class-name enumeration
16701/// binds against this same axis, a future per-`Gateway` typed-listener
16702/// TLS terminator renderer whose per-Gateway `spec` block nests
16703/// alongside this same axis) inherits the same value by construction
16704/// with no opportunity for per-renderer drift.
16705///
16706/// [cm]: ../../caixa_mesh/index.html
16707pub const GATEWAY_API_KEY_GATEWAY_CLASS_NAME: &str = "gatewayClassName";
16708
16709/// Canonical K8s Gateway API `HTTPRoute` per-`HTTPRouteMatch` path-matcher
16710/// container-axis key every `gateway_routes`-emitted `HTTPRoute` per-rule
16711/// `matches[]` entry mounts its per-match `{type, value}` path-selection
16712/// predicate under (`spec.rules[].matches[].path`). Nests one level
16713/// beneath the sibling [`GATEWAY_API_KEY_MATCHES`] (b9ede1a) per-rule
16714/// route-match container-axis it hangs off of — the Gateway API v1 CRD
16715/// schema pins per-`HTTPRouteMatch` request-path selection through the
16716/// `spec.rules[].matches[].path` container axis (each match entry names
16717/// one path-selection predicate the request line's `:path` pseudo-header
16718/// must satisfy under a `type` discriminator of
16719/// `Exact | PathPrefix | RegularExpression`) alongside the sibling per-
16720/// `HTTPRouteMatch` `headers[]` / `queryParams[]` / `method` axes it
16721/// nests under, so drift on the per-match path-matcher container axis
16722/// is exactly as load-bearing as drift on the per-rule route-match
16723/// axis it nests inside of (the K8s apiserver-side Gateway API CRD
16724/// schema validator drops any per-match block whose path-matcher
16725/// container axis carries an unrecognized key — a `"pathMatch"` /
16726/// `"prefix"` / `"url"` typo silently emits an `HTTPRoute` whose per-
16727/// match path-selection axis the Gateway API implementation's per-rule
16728/// L7 dispatch loop no-ops entirely: no path predicate is evaluated,
16729/// the match degrades to the wildcard predicate at the gateway-class-
16730/// controller's per-rule reconcile, the rule matches every request
16731/// path unconditionally, and every external `:entrada` path filter the
16732/// rule was authored to enforce drops with no field naming the path-
16733/// matcher-axis-drift root cause).
16734///
16735/// The single source of truth the rendered Aplicacao Gateway-API-side
16736/// ingress bundle's per-`HTTPRouteMatch` path-matcher-container-axis-
16737/// naming reaches for:
16738///
16739///   - the rendered `HTTPRoute` document's per-match
16740///     `spec.rules[].matches[].path` axis (caixa-mesh/src/lib.rs — the
16741///     `gateway_routes` per-Aplicacao `HTTPRoute`'s per-match
16742///     `match_entry.insert("path", …)` call seeded from the Aplicacao's
16743///     `:entrada :paths` slot).
16744///
16745/// The per-`HTTPRouteMatch` path-matcher container axis names the same
16746/// Gateway-API-implementation-side per-match request-path-selection
16747/// predicate container as the sibling
16748/// [`GATEWAY_API_KEY_MATCHES`] per-rule route-match container axis it
16749/// nests inside of, and must move together on any future Gateway API
16750/// rebrand (an upstream SIG-Network Gateway API v2 rename of the path-
16751/// matcher axis from `path` to `pathMatch` / `prefix` / `url`,
16752/// coordinated with the Gateway API deprecation cycle). Until this lift
16753/// landed the axis carried an inline `path` literal at the one
16754/// production-code occurrence in caixa-mesh/src/lib.rs (the
16755/// `gateway_routes` per-match `match_entry.insert("path", …)` call) —
16756/// one occurrence of the same load-bearing Gateway-API-CRD-
16757/// `path`-axis-key convention, drift-prone by construction. A drift on
16758/// the production site to `"pathMatch"` / `"prefix"` / `"url"` would
16759/// have surfaced as a Gateway API implementation-side schema validator
16760/// drop at apply time (the affected per-match path-matcher axis the
16761/// CRD schema validator recognizes as unknown), with the per-match
16762/// path predicate degrading to the wildcard match at the gateway-
16763/// class-controller's per-rule reconcile with no field naming the
16764/// path-matcher-drift root cause.
16765///
16766/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
16767/// "every recurring shape becomes a generator before it becomes a
16768/// pattern; every pattern becomes a library before it becomes
16769/// duplicated code. The duplication budget is zero.") promotes the
16770/// constant to a typed substrate-side `&'static str` on the same
16771/// trajectory the [`GATEWAY_API_KEY_MATCHES`] (b9ede1a) /
16772/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
16773/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
16774/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
16775/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
16776/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
16777/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
16778/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
16779/// [`GATEWAY_API_KEY_GATEWAY_CLASS_NAME`] (1bc727d) lifts established on
16780/// the sibling canonical-Gateway-API-HTTPRoute-body-axis / per-Gateway-
16781/// body-axis surfaces — nests the per-Gateway-API-HTTPRoute-per-rule-
16782/// body-axis canonical-string-pin set (`matches`, `backendRefs`,
16783/// `timeouts`, `retry`) one level deeper onto the per-`HTTPRouteMatch`
16784/// body-axis surface, so the container-axis key beneath the sibling
16785/// `matches[]` axis now threads a lifted `&'static str` alongside its
16786/// parent-container-axis key. The render-side consumer now threads the
16787/// same `&'static str` through its `match_entry.insert(…)` call so a
16788/// future Gateway API rebrand on the per-`HTTPRouteMatch` path-matcher
16789/// axis (or an upstream SIG-Network Gateway API v2 rename to a per-
16790/// `HTTPRouteMatch` sibling name) lands in one place; every future
16791/// renderer that reaches for the canonical per-`HTTPRouteMatch` path-
16792/// matcher axis (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
16793/// materializer's per-Aplicacao `HTTPRoute` fan-out, a future per-edge
16794/// `GRPCRoute` renderer whose per-match request-method / service /
16795/// method predicate nests alongside the path predicate, a future
16796/// per-match header-match / query-match renderer whose per-predicate
16797/// list binds against sibling axes of this one under the same match
16798/// entry) inherits the same value by construction with no opportunity
16799/// for per-renderer drift.
16800///
16801/// Same "the typed constant lives in one place" discipline the
16802/// [`GATEWAY_API_KEY_MATCHES`] (b9ede1a) /
16803/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
16804/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
16805/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
16806/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
16807/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
16808/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
16809/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
16810/// [`GATEWAY_API_KEY_GATEWAY_CLASS_NAME`] (1bc727d) lifts apply on the
16811/// peer canonical-Gateway-API-HTTPRoute-per-`HTTPRouteMatch`-body-axis
16812/// surface.
16813///
16814/// [cm]: ../../caixa_mesh/index.html
16815pub const GATEWAY_API_KEY_PATH: &str = "path";
16816
16817/// Canonical K8s Gateway API v1 `HTTPPathMatch` `value` scalar-axis key
16818/// every `gateway_routes`-emitted `HTTPRoute` per-match `path` block
16819/// mounts its request-path-selection scalar payload under
16820/// (`spec.rules[].matches[].path.value`). Nests one level beneath the
16821/// sibling [`GATEWAY_API_KEY_PATH`] per-`HTTPRouteMatch` path-matcher
16822/// container-axis it hangs off of — the Gateway API v1 CRD schema
16823/// pins per-`HTTPPathMatch` request-path selection through the
16824/// `{type, value}` two-axis pair (a
16825/// [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`]-typed `type`
16826/// discriminator picks `Exact | PathPrefix | RegularExpression`; the
16827/// `value` scalar carries the per-match request-path string the
16828/// discriminator is applied against), so drift on the `value` scalar
16829/// axis is exactly as load-bearing as drift on the peer `type`
16830/// discriminator axis it nests alongside (the K8s apiserver-side
16831/// Gateway API CRD schema validator drops any per-match block whose
16832/// `HTTPPathMatch` scalar-payload axis carries an unrecognized key —
16833/// a `"path"` / `"prefix"` / `"pattern"` typo silently emits an
16834/// `HTTPRoute` whose per-match request-path predicate the Gateway API
16835/// implementation's per-rule L7 dispatch loop treats as bare (no
16836/// value evaluated against the `type` discriminator), the match
16837/// degrades to the wildcard predicate at the gateway-class-
16838/// controller's per-rule reconcile, the rule matches every request
16839/// path unconditionally, and every external `:entrada` path filter the
16840/// rule was authored to enforce drops with no field naming the
16841/// `HTTPPathMatch`-scalar-payload-drift root cause).
16842///
16843/// The single source of truth the rendered Aplicacao Gateway-API-side
16844/// ingress bundle's per-`HTTPPathMatch` scalar-payload-axis-naming
16845/// reaches for:
16846///
16847///   - the rendered `HTTPRoute` document's per-match
16848///     `spec.rules[].matches[].path.value` axis (caixa-mesh/src/lib.rs
16849///     — the `gateway_routes` per-Aplicacao `HTTPRoute`'s per-match
16850///     `path_match.insert("value", …)` call seeded from the
16851///     Aplicacao's `:entrada :paths` slot).
16852///
16853/// The per-`HTTPPathMatch` scalar-payload axis names the same
16854/// Gateway-API-implementation-side per-match request-path-selection
16855/// scalar as the sibling [`GATEWAY_API_KEY_PATH`] per-`HTTPRouteMatch`
16856/// path-matcher container-axis it nests inside of, and must move
16857/// together on any future Gateway API rebrand (an upstream
16858/// SIG-Network Gateway API v2 rename of the `HTTPPathMatch` scalar-
16859/// payload axis from `value` to `path` / `pattern` / `expression`,
16860/// coordinated with the Gateway API deprecation cycle). Until this
16861/// lift landed the axis carried an inline `"value"` literal at the
16862/// one production-code occurrence in caixa-mesh/src/lib.rs (the
16863/// `gateway_routes` per-match `path_match.insert("value", …)` call) —
16864/// one occurrence of the same load-bearing Gateway-API-CRD-
16865/// `HTTPPathMatch`-`value`-axis-key convention, drift-prone by
16866/// construction. A drift on the production site to `"path"` /
16867/// `"prefix"` / `"pattern"` would have surfaced as a Gateway API
16868/// implementation-side schema validator drop at apply time (the
16869/// affected per-match `HTTPPathMatch` scalar-payload axis the CRD
16870/// schema validator recognizes as unknown), with the per-match path
16871/// predicate degrading to the wildcard match at the gateway-class-
16872/// controller's per-rule reconcile with no field naming the
16873/// `HTTPPathMatch`-scalar-payload-drift root cause.
16874///
16875/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
16876/// "every recurring shape becomes a generator before it becomes a
16877/// pattern; every pattern becomes a library before it becomes
16878/// duplicated code. The duplication budget is zero.") promotes the
16879/// constant to a typed substrate-side `&'static str` on the same
16880/// trajectory the [`GATEWAY_API_KEY_PATH`] (9f45aa4) /
16881/// [`GATEWAY_API_KEY_MATCHES`] (b9ede1a) /
16882/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
16883/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
16884/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
16885/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
16886/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
16887/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
16888/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
16889/// [`GATEWAY_API_KEY_GATEWAY_CLASS_NAME`] (1bc727d) lifts established
16890/// on the sibling canonical-Gateway-API-body-axis surfaces — nests
16891/// the per-Gateway-API-HTTPRoute-per-match-body-axis canonical-
16892/// string-pin set (`path` container-axis, `type` discriminator
16893/// scalar-key, `value` scalar-payload key) two levels deeper onto the
16894/// per-`HTTPPathMatch` body-axis surface, so both halves of the
16895/// `HTTPPathMatch.{type, value}` typed contract now thread one lifted
16896/// `&'static str` apiece at the substrate boundary alongside the
16897/// parent-container-axis key. The render-side consumer now threads
16898/// the same `&'static str` through its `path_match.insert(…)` call
16899/// so a future Gateway API rebrand on the `HTTPPathMatch` scalar-
16900/// payload axis (or an upstream SIG-Network Gateway API v2 rename to
16901/// a per-`HTTPPathMatch` sibling name) lands in one place; every
16902/// future renderer that reaches for the canonical per-`HTTPPathMatch`
16903/// scalar-payload axis (the future M4
16904/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
16905/// `HTTPRoute` fan-out, a future per-edge `GRPCRoute` renderer whose
16906/// per-match `GRPCMethodMatch.method` scalar-payload nests alongside
16907/// this same axis, a future per-match header-match / query-match
16908/// renderer whose per-predicate `HTTPHeaderMatch.value` /
16909/// `HTTPQueryParamMatch.value` scalar-payload binds against sibling
16910/// axes on the same `value` axis-key) inherits the same value by
16911/// construction with no opportunity for per-renderer drift.
16912///
16913/// [cm]: ../../caixa_mesh/index.html
16914pub const GATEWAY_API_KEY_VALUE: &str = "value";
16915
16916/// Canonical K8s Gateway API v1 per-child-object name-reference
16917/// discriminator axis key every `gateway_routes`-emitted `Gateway`
16918/// listener + `HTTPRoute` `parentRefs[]` / `backendRefs[]` entry
16919/// mounts its named-object binding under. Three peer sub-schemas on
16920/// the shared `spec.…[].name` axis:
16921///
16922///   - `Gateway.spec.listeners[].name` — Gateway API v1 `SectionName`,
16923///     the listener's per-section identifier the sibling
16924///     `HTTPRoute.spec.parentRefs[].sectionName` binds against;
16925///   - `HTTPRoute.spec.parentRefs[].name` — Gateway API v1
16926///     `ObjectName`, the per-`HTTPRoute` parent-Gateway reference the
16927///     Gateway API implementation's per-HTTPRoute attach reconciler
16928///     resolves against a `Gateway` object in the same namespace;
16929///   - `HTTPRoute.spec.rules[].backendRefs[].name` — Gateway API v1
16930///     `ObjectName`, the per-rule backend-Service reference the
16931///     Gateway API implementation's per-rule L7 dispatch loop
16932///     resolves against a `Service` object in the same namespace.
16933///
16934/// All three sub-schemas key their named-reference discriminator on
16935/// the identical three-byte `"name"` axis at every level of the
16936/// Gateway API v1 CRD schema (`Gateway.spec.listeners[].name`,
16937/// `HTTPRoute.spec.parentRefs[].name`,
16938/// `HTTPRoute.spec.rules[].backendRefs[].name`), so drift on any one
16939/// of them silently splits the substrate's Aplicacao gateway bundle
16940/// at whichever schema the drift hits (the K8s apiserver-side Gateway
16941/// API CRD schema validator drops a per-listener / per-parentRef /
16942/// per-backendRef block whose name-reference axis carries an
16943/// unrecognized key — a `"Name"` / `"target"` / `"ref"` typo silently
16944/// emits a `Gateway` whose listener carries no section identity, or
16945/// an `HTTPRoute` whose parent-Gateway attachment reconciles as
16946/// unbound, or an `HTTPRoute` whose per-rule backend fan-out resolves
16947/// no Service, and every external `:entrada` flow the bundle was
16948/// authored to accept drops at the gateway-class-controller's per-
16949/// rule/per-listener/per-parentRef reconcile with no field naming the
16950/// name-reference-axis-drift root cause).
16951///
16952/// The single source of truth the rendered Aplicacao Gateway-API-side
16953/// ingress bundle's per-child-object name-reference-axis-naming
16954/// reaches for:
16955///
16956///   - the rendered `Gateway` document's `spec.listeners[].name` axis
16957///     (caixa-mesh/src/lib.rs — the `gateway_routes` per-Aplicacao
16958///     `Gateway`'s per-listener `listener.insert("name", …)` call);
16959///   - the rendered `HTTPRoute` document's `spec.parentRefs[].name`
16960///     axis (caixa-mesh/src/lib.rs — the `gateway_routes` per-
16961///     Aplicacao `HTTPRoute`'s per-parentRef
16962///     `parent_ref.insert("name", …)` call);
16963///   - the rendered `HTTPRoute` document's
16964///     `spec.rules[].backendRefs[].name` axis (caixa-mesh/src/lib.rs
16965///     — the `gateway_routes` per-rule per-backendRef
16966///     `backend_ref.insert("name", …)` call).
16967///
16968/// The per-child-object name-reference discriminator axis names the
16969/// same Gateway-API-implementation-side named-object binding container
16970/// as the sibling [`GATEWAY_API_KEY_LISTENERS`] +
16971/// [`GATEWAY_API_KEY_PARENT_REFS`] + [`GATEWAY_API_KEY_BACKEND_REFS`]
16972/// per-container list axes it nests directly beneath, and must move
16973/// together on any future Gateway API rebrand (an upstream SIG-Network
16974/// Gateway API v2 rename of the name-reference axis from `name` to
16975/// `target` / `ref` / `objectName`, coordinated with the Gateway API
16976/// deprecation cycle). Until this lift landed the axis carried inline
16977/// `"name"` literals at four occurrences across caixa-mesh — three
16978/// production emitter sites (the per-listener `listener.insert("name",
16979/// …)`, the per-parentRef `parent_ref.insert("name", …)`, and the per-
16980/// backendRef `backend_ref.insert("name", …)` calls in
16981/// `gateway_routes`) plus one in-file test-fixture navigation (the
16982/// `httproute_routes_to_entrada_para` fixture's per-backendRef
16983/// `.get("name")` retrieval) — four occurrences of the same load-
16984/// bearing Gateway-API-CRD-`name`-axis-key convention, drift-prone by
16985/// construction. A drift on any one production site to `"Name"` /
16986/// `"target"` / `"ref"` would have surfaced as a Gateway API
16987/// implementation-side schema validator drop at apply time (the
16988/// affected per-listener / per-parentRef / per-backendRef name-
16989/// reference axis the CRD schema validator recognizes as unknown),
16990/// with the listener carrying no section identity or the `HTTPRoute`
16991/// carrying an unbound parent-Gateway attachment or the per-rule
16992/// backend fan-out resolving no Service at the gateway-class-
16993/// controller's reconcile with no field naming the name-reference-
16994/// drift root cause. A drift on the test-fixture side silently masks
16995/// the emission-side pin (`.get("name")` returns `None` under both
16996/// the drifted-key emitter and the drifted-key probe — the downstream
16997/// `.and_then(|n| n.as_str())` chain short-circuits vacuously because
16998/// the outer per-backendRef name-reference lookup is itself `None`).
16999///
17000/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
17001/// "every recurring shape becomes a generator before it becomes a
17002/// pattern; every pattern becomes a library before it becomes
17003/// duplicated code. The duplication budget is zero.") promotes the
17004/// constant to a typed substrate-side `&'static str` on the same
17005/// trajectory the [`GATEWAY_API_KEY_PATH`] (9f45aa4) /
17006/// [`GATEWAY_API_KEY_MATCHES`] (b9ede1a) /
17007/// [`GATEWAY_API_KEY_BACKEND_REFS`] (a6c5679) /
17008/// [`GATEWAY_API_KEY_PARENT_REFS`] (f44e823) /
17009/// [`GATEWAY_API_KEY_LISTENERS`] (29f2415) /
17010/// [`GATEWAY_API_KEY_HOSTNAMES`] (b77f744) /
17011/// [`GATEWAY_API_KEY_HOSTNAME`] (c96fa22) /
17012/// [`GATEWAY_API_KEY_TIMEOUTS`] (db31108) /
17013/// [`GATEWAY_API_KEY_RETRY`] (231bbf5) /
17014/// [`GATEWAY_API_KEY_GATEWAY_CLASS_NAME`] (1bc727d) lifts established
17015/// on the sibling canonical-Gateway-API-CRD-body-axis surface —
17016/// completes the four-way per-child-object axis-key set (`name` on
17017/// listeners + parentRefs + backendRefs, alongside sibling
17018/// `hostname`/`port`/`protocol` per-listener and `port` per-
17019/// backendRef) the M3 Aplicacao mesh renderer's external `:entrada`
17020/// ingress contract rests on. The render-side consumer now threads
17021/// the same `&'static str` through every one of its `.insert(…)`
17022/// calls so a future Gateway API rebrand on the name-reference axis
17023/// (or an upstream SIG-Network Gateway API v2 rename to a per-CRD
17024/// sibling name) lands in one place; every future renderer that
17025/// reaches for the canonical per-child-object name-reference axis
17026/// (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
17027/// materializer's per-Aplicacao `Gateway` + `HTTPRoute` fan-out, a
17028/// future per-edge `GRPCRoute` / `TCPRoute` / `TLSRoute` renderer
17029/// whose per-rule backend-Service reference binds against this same
17030/// axis, a future per-Aplicacao `ReferenceGrant` renderer whose per-
17031/// cross-namespace parent-Gateway attachment resolves against this
17032/// same axis) inherits the same value by construction with no
17033/// opportunity for per-renderer drift.
17034///
17035/// Byte-identical to [`KUBE_KEY_NAME`] today — both resolve to the
17036/// same three-byte `"name"` literal — but semantically distinct:
17037/// [`KUBE_KEY_NAME`] names the K8s CR canonical `metadata.name` axis
17038/// (every rendered CR's outer-level identity discriminator, spelled
17039/// per the K8s apiserver's per-object `OpenAPI` v3 schema), while this
17040/// constant names the Gateway API v1 CRD schema's per-child-object
17041/// name-reference discriminator axis on `Listener` / `ParentReference`
17042/// / `BackendObjectReference` sub-schemas (spelled per the Gateway API
17043/// v1 CRD schema — a separate schema contract). Splitting the two
17044/// lets each schema's future rebrand land independently at its
17045/// canonical const definition without coupling the K8s CR canonical-
17046/// key axis to the Gateway API v1 per-child-object name-reference
17047/// axis (or vice versa) — the same discipline
17048/// [`FLEET_PROGRAMS_KEY_NAME`] establishes vs. [`KUBE_KEY_NAME`] on
17049/// the `lareira-fleet-programs` values-schema per-entry name-axis.
17050///
17051/// [cm]: ../../caixa_mesh/index.html
17052pub const GATEWAY_API_KEY_NAME: &str = "name";
17053
17054/// Canonical Helm 3 `Chart.yaml` `apiVersion` every `caixa-helm`-rendered
17055/// `lareira-<nome>` chart declares at its top-level `apiVersion` axis. The
17056/// Helm 3 chart-schema resolution contract keys off this exact `"v2"` value:
17057/// `helm dependency build`, `helm lint`, and `helm template` all parse the
17058/// chart under the Helm 3 v2 schema (which requires
17059/// [`ChartYaml::description`][chart-yaml-desc] and permits
17060/// `dependencies:` at the top level); drift to the legacy Helm 2 `"v1"`
17061/// (the pre-Helm-3 chart schema every upstream Helm-3-migration doc names)
17062/// silently reroutes the rendered `Chart.yaml` through the Helm 2 parser,
17063/// where the top-level `dependencies:` block is unknown and the chart's
17064/// dep on the `pleme-computeunit` library chart never resolves —
17065/// `helm dependency build` reports "no requirements found" and every
17066/// downstream `helm template` / `helm install` on the rendered chart
17067/// emits an empty release (no ComputeUnit / Service / ScaledObject
17068/// resources land) far from the source caixa.lisp / the renderer's
17069/// `build_chart_yaml` call site.
17070///
17071/// The single source of truth the [`caixa-helm`][ch]'s `build_chart_yaml`
17072/// `Chart.yaml` `apiVersion` axis reaches for (caixa-helm/src/lib.rs:298).
17073/// Peer with the [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
17074/// [`FLUX_GITREPOSITORY_API_VERSION`] (dbbcf29) /
17075/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
17076/// [`GATEWAY_API_API_VERSION`] (3c6cfc3) / [`CILIUM_API_VERSION`] (279d611)
17077/// lifts on the sibling cluster-side-CRD-apiVersion surface — those pin
17078/// the K8s apiserver-side `(apiVersion, kind)` `RESTMapper` contract,
17079/// this one pins the Helm-side chart-schema-parser contract that gates
17080/// every rendered `lareira-<nome>` chart's dependency resolution before
17081/// any K8s resource lands. Both axes are load-bearing schema-version
17082/// discriminators drift-prone by construction across renderer forks.
17083///
17084/// A future Helm 4 chart-schema promotion (the upstream Helm roadmap
17085/// names a `"v3"` apiVersion once the Helm 3 LTS branch closes) is a
17086/// coordinated migration alongside the upstream Helm chart-schema
17087/// deprecation cycle, not an incidental edit — pinning it here means
17088/// the migration lands as one edit at the const + a re-run of the
17089/// pin tests rather than a per-renderer sweep with no single source
17090/// of truth to consult. Same "the typed constant lives in one place"
17091/// discipline the [`DEFAULT_LIBRARY_NAME`] (41438dc) /
17092/// [`LAREIRA_CHART_NAME_PREFIX`] / [`FLUX_HELMRELEASE_API_VERSION`]
17093/// (55f0fd9) lifts apply on the peer canonical-Helm-load-bearing-string
17094/// and cluster-side-CRD-apiVersion axes.
17095///
17096/// [chart-yaml-desc]: https://helm.sh/docs/topics/charts/#the-chartyaml-file
17097/// [ch]: ../../caixa_helm/index.html
17098pub const HELM_CHART_API_VERSION: &str = "v2";
17099
17100/// Canonical Helm 3 `Chart.yaml` `type` field per-chart-kind discriminator
17101/// scalar-value every rendered `lareira-<nome>` chart declares. The Helm
17102/// chart-schema pins the per-chart-kind axis to the closed set
17103/// `{"application", "library"}` (see [chart-type-doc]) — the
17104/// `application` chart-kind is Helm's default install-shape (an
17105/// application chart that installs into a namespace as a workload +
17106/// rendered manifests), while the `library` chart-kind is Helm's
17107/// dependency-only shape (a chart authored as a shared-template
17108/// substrate that can only be consumed as a dependency, never installed
17109/// directly). Each `lareira-<nome>` chart the caixa-helm renderer emits
17110/// declares itself as an `application` chart because it is the per-
17111/// Servico install shape a cluster operator's `helm install` /
17112/// `helm upgrade` per-Servico release cycle materializes — the sibling
17113/// [`DEFAULT_LIBRARY_NAME`] `pleme-computeunit` chart (the substrate-
17114/// side library-chart the `lareira-<nome>` chart depends on for
17115/// template-shape) carries the sibling `library` value verbatim in its
17116/// authored Chart.yaml (out-of-tree at the `pleme-io/helmworks` repo,
17117/// so not this crate's authority).
17118///
17119/// The single source of truth the rendered `lareira-<nome>` chart's
17120/// Chart.yaml per-chart-kind discriminator axis naming reaches for:
17121///
17122///   - [`caixa-helm`][ch]'s `build_chart_yaml` `chart_type` field
17123///     assignment (caixa-helm/src/lib.rs — the sole production emitter
17124///     site the prior inline `"application".into()` literal sat at,
17125///     writing the per-chart-kind discriminator scalar-value the
17126///     `helm install` / `helm upgrade` per-release install-shape dispatch
17127///     loop keys off to select the per-chart-kind install pathway).
17128///
17129/// Until this lift landed the axis carried an inline `"application"`
17130/// literal at the one production-code site (`build_chart_yaml`'s
17131/// `chart_type` field assignment). A drift on the value at the emitter
17132/// (a `"Application"` / `"APPLICATION"` / `"app"` / `"workload"` typo,
17133/// or an accidental collapse onto the sibling `"library"` shape) would
17134/// have surfaced as one of two silent failure modes at `helm install`
17135/// time:
17136///
17137///   - a value outside the schema's admitted set (`{"application",
17138///     "library"}`) — Helm's chart-schema parser silently treats an
17139///     unrecognized `type:` scalar as the default `application` shape,
17140///     so a typo like `"Application"` still installs but with no
17141///     drift-signal in the process log, silently masking the schema
17142///     violation;
17143///   - a schema-admitted-but-wrong-shape drift onto `"library"` —
17144///     `helm install lareira-<nome>` refuses the release with an
17145///     "Error: library charts cannot be installed" error, and the
17146///     per-Servico release cycle drops with no field naming the
17147///     chart-kind-drift root cause (the operator sees "the chart won't
17148///     install" far from the drift site, and troubleshooting has no
17149///     canonical anchor to compare the rendered value against).
17150///
17151/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
17152/// "every recurring shape becomes a generator before it becomes a
17153/// pattern; every pattern becomes a library before it becomes
17154/// duplicated code. The duplication budget is zero.") promotes the
17155/// constant to a typed substrate-side `&'static str` on the same
17156/// trajectory the peer [`HELM_CHART_API_VERSION`] /
17157/// [`DEFAULT_LIBRARY_NAME`] / [`LAREIRA_CHART_NAME_PREFIX`] lifts
17158/// established on the sibling canonical-Helm-load-bearing-string axes —
17159/// extends the canonical-Helm-chart-schema-axis single-sourcing
17160/// discipline the `apiVersion` lift established onto the sibling
17161/// per-chart-kind discriminator scalar-value axis every rendered
17162/// `lareira-<nome>` chart declares in its Chart.yaml. Peer to the
17163/// canonical-cluster-side-OpenAPI-schema-enum-value lifts
17164/// ([`KUBE_PROTOCOL_TCP`] / [`GATEWAY_API_PROTOCOL_HTTP`] /
17165/// [`GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX`] /
17166/// [`CILIUM_AUTH_MODE_REQUIRED`] / [`CILIUM_AUTH_MODE_DISABLED`]) on
17167/// the sibling K8s-CR-side enum-value surfaces — pivots the discipline
17168/// from the K8s-CR-side OpenAPI-schema-enum-value axis onto the
17169/// Helm-chart-schema-enum-value axis every rendered Chart.yaml carries
17170/// at its per-chart-kind discriminator field.
17171///
17172/// [chart-type-doc]: https://helm.sh/docs/topics/charts/#chart-types
17173/// [ch]: ../../caixa_helm/index.html
17174pub const HELM_CHART_TYPE_APPLICATION: &str = "application";
17175
17176/// Canonical Helm 3 `Chart.yaml` `type` field per-chart-kind discriminator
17177/// scalar-value the sibling library-chart shape lands on — the second and
17178/// only other arm of the closed set `{"application", "library"}` the Helm
17179/// chart-schema pins the per-chart-kind axis to (see [chart-type-doc]).
17180/// The `library` chart-kind is Helm's dependency-only install-shape: a
17181/// chart authored as a shared-template substrate the per-Aplicacao
17182/// `lareira-<nome>` application charts depend on for their emitted-
17183/// object templates (the [`DEFAULT_LIBRARY_NAME`] `pleme-computeunit`
17184/// chart out-of-tree at `pleme-io/helmworks` is the substrate's
17185/// canonical instance today), and Helm refuses to install it directly
17186/// (`helm install <library-chart>` fails with "Error: library charts
17187/// cannot be installed") — a chart declaring itself under this
17188/// scalar-value is only ever consumed as a dependency by a sibling
17189/// `application`-typed chart.
17190///
17191/// Peer of [`HELM_CHART_TYPE_APPLICATION`] on the same closed
17192/// canonical-Helm-chart-schema-per-chart-kind-discriminator axis: the
17193/// two consts together name the two-arm schema-admitted set as a pair
17194/// of `&'static str`s at the substrate-side canonical surface, so any
17195/// consumer that reaches for either shape (the caixa-helm renderer at
17196/// [`HELM_CHART_TYPE_APPLICATION`]'s single emitter site today; the
17197/// future per-Aplicacao library chart the [`HELM_CHART_TYPE_APPLICATION`]
17198/// docstring names as a trajectory item, whose emit site would land at
17199/// this const; the future `mesh.pleme.io/v1alpha1/Aplicacao` CR
17200/// materializer's per-chart-kind admission gate that needs to accept
17201/// exactly the two-arm closed set) reads from one canonical declaration
17202/// per arm, not a scattered mix of substrate-side const + prose-only
17203/// sibling. Same "one canonical declaration per arm, next to the
17204/// closed set's peer" discipline the peer
17205/// [`CILIUM_AUTH_MODE_REQUIRED`] / [`CILIUM_AUTH_MODE_DISABLED`]
17206/// (2c3f11b — the two-arm Cilium `MutualAuthenticationMode` `OpenAPI`
17207/// enum's closed set) established for the sibling Cilium-CR-side
17208/// per-enum-value axis, and the peer
17209/// [`M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE`] /
17210/// [`M3_PLACEMENT_ESTRATEGIA_REPLICATED`] /
17211/// [`M3_PLACEMENT_ESTRATEGIA_SHARDED`] (b0ce0a5 — the three-arm typed
17212/// [`crate::PlacementStrategy`] variant discriminator-value set) applies
17213/// on the sibling M3 typed-enum discriminator-scalar axis — extends the
17214/// discipline onto the Helm-chart-schema-enum-value closed set every
17215/// rendered Chart.yaml declares its per-chart-kind axis over.
17216///
17217/// Until this lift landed the sibling `"library"` value lived only in
17218/// prose across the [`HELM_CHART_TYPE_APPLICATION`] docstring's
17219/// closed-set enumeration (3+ mentions naming the sibling `library`
17220/// shape as the schema-admitted second arm, including the accidental-
17221/// collapse-onto-sibling failure-mode arm the pin test
17222/// [`tests::helm_chart_type_application_and_library_are_distinct`]
17223/// closes), with no compile-time link between the substrate-side
17224/// canonical const and the sibling closed-set arm the docstring
17225/// referenced — a hypothetical future consumer reaching for the
17226/// sibling shape (an operator-side per-chart-kind classifier, a
17227/// helmworks-side value-drift detector, the future per-Aplicacao
17228/// library chart's emit site) had to re-derive the value from the
17229/// prose enumeration rather than reading the same `&'static str` the
17230/// substrate declares. This lift closes that gap by pairing the
17231/// canonical-Helm-chart-schema-per-chart-kind axis at both closed-set
17232/// arms, so drift-detection between the two shapes is a build-time
17233/// constant-value comparison at
17234/// [`tests::helm_chart_type_application_and_library_are_distinct`]
17235/// rather than a runtime silent-collapse-onto-sibling far from the
17236/// drift's source.
17237///
17238/// [chart-type-doc]: https://helm.sh/docs/topics/charts/#chart-types
17239pub const HELM_CHART_TYPE_LIBRARY: &str = "library";
17240
17241/// Canonical Helm 3 `Chart.yaml` top-level YAML axis-key naming the
17242/// per-chart chart-schema-apiVersion field whose scalar-value
17243/// [`HELM_CHART_API_VERSION`] already owns as the peer axis-value
17244/// lift. Where the peer axis-value lift pins the byte-shape of the
17245/// `apiVersion:` field's admitted scalar (Helm 3's `"v2"`), this
17246/// axis-key lift pins the byte-shape of the `apiVersion:` field's
17247/// YAML-key name itself: the load-bearing serde-rename literal at
17248/// [`caixa-helm`][ch]'s `ChartYaml` struct
17249/// (`caixa-helm/src/lib.rs:145`, `#[serde(rename = "apiVersion")]`)
17250/// that selects how the Rust field `api_version` serializes into
17251/// the rendered `Chart.yaml` YAML mapping.
17252///
17253/// The byte-shape (`"apiVersion"`) is byte-identical to the K8s-CR
17254/// top-level per-CR schema-apiVersion axis key ([`KUBE_KEY_API_VERSION`])
17255/// by Helm's design decision to inherit the K8s CR top-level shape
17256/// verbatim (see [chart-yaml-desc]) — the paired
17257/// `helm_chart_key_api_version_matches_kube_key_api_version` pin
17258/// asserts the two byte-shapes coincide, so a future K8s-side
17259/// rebrand at [`KUBE_KEY_API_VERSION`] that dropped the byte-
17260/// identity would fail the pin, surfacing the axis divergence at
17261/// substrate-build time rather than as a silent Helm-chart-schema-
17262/// parser rejection at `helm lint` / `helm template` time. The two
17263/// axes are structurally-independent schema surfaces (the Helm 3
17264/// chart-schema top-level shape vs. the K8s apiserver-side CR
17265/// top-level shape) whose byte-shapes happen to coincide today; the
17266/// paired pin makes the coincidence load-bearing rather than
17267/// accidental.
17268///
17269/// The single source of truth every consumer that names the per-
17270/// Chart.yaml top-level chart-schema-apiVersion YAML key reaches for:
17271///
17272///   - [`caixa-helm`][ch]'s `ChartYaml` struct's `api_version` field
17273///     `#[serde(rename = "apiVersion")]` attribute (the sole
17274///     production serialize-side site the literal appears at as a
17275///     syntactic serde-rename argument; the attribute itself cannot
17276///     consume a `const` because Rust's attribute grammar admits
17277///     only string literals, so the discipline here is: the const's
17278///     byte-shape must remain byte-identical to the literal the
17279///     attribute pins, and the paired drift-detection pin at
17280///     [`caixa-helm`]'s
17281///     `chart_yaml_serializes_api_version_axis_under_lifted_helm_chart_key_api_version`
17282///     round-trips a rendered [`caixa-helm`]-emitted `Chart.yaml`
17283///     through `serde_yaml::from_str::<serde_yaml::Value>` and
17284///     asserts the top-level `Mapping::get(HELM_CHART_KEY_API_VERSION)`
17285///     resolves — closing the drift the syntactic-literal-only
17286///     attribute would otherwise leave silent);
17287///   - every test-side navigator that inspects the serialized
17288///     [`caixa-helm`]-emitted `Chart.yaml` YAML mapping by the top-
17289///     level chart-schema-apiVersion key.
17290///
17291/// A drift on the emitter's serde-rename literal (a future refactor
17292/// that dropped the `#[serde(rename = "apiVersion")]` attribute or
17293/// changed the target key to `"ApiVersion"` / `"apiversion"` /
17294/// `"schemaVersion"`) would silently serialize the field under
17295/// Rust's default snake_case `api_version:` key, which Helm's
17296/// chart-schema parser rejects at `helm lint` / `helm dependency
17297/// build` / `helm template` time with an "apiVersion is required"
17298/// error — the failure surfaces far from the drift site, and every
17299/// downstream `lareira-<nome>` chart consumer drops with no field
17300/// naming the serde-rename-drift root cause. Same drift-detection-
17301/// pin discipline the peer [`HELM_CHART_KEY_TYPE`] /
17302/// [`HELM_CHART_KEY_APP_VERSION`] lifts (d29bc23) established on the
17303/// sibling per-Chart.yaml serde-rename-literal-only axis pair —
17304/// extends the discipline from the two axes those lifts closed onto
17305/// the third and last serde-rename-literal-only axis at
17306/// [`caixa-helm`]'s `ChartYaml` struct, so every `#[serde(rename =
17307/// "...")]` literal on the struct threads through a canonical
17308/// substrate-side `&'static str` with a paired drift-detection pin.
17309///
17310/// [chart-yaml-desc]: https://helm.sh/docs/topics/charts/#the-chartyaml-file
17311/// [ch]: ../../caixa_helm/index.html
17312pub const HELM_CHART_KEY_API_VERSION: &str = "apiVersion";
17313
17314/// Canonical Helm 3 `Chart.yaml` top-level YAML axis-key naming the
17315/// per-chart-kind discriminator field whose closed-set scalar-value
17316/// pair [`HELM_CHART_TYPE_APPLICATION`] / [`HELM_CHART_TYPE_LIBRARY`]
17317/// already owns as the peer axis-value lift. Where the peer
17318/// axis-value lifts pin the byte-shape of the `type:` field's
17319/// admitted-value set, this axis-key lift pins the byte-shape of the
17320/// `type:` field's YAML-key name itself: the load-bearing serde-
17321/// rename literal at [`caixa-helm`][ch]'s `ChartYaml` struct
17322/// (`caixa-helm/src/lib.rs:149`, `#[serde(rename = "type")]`) that
17323/// selects how the Rust field `chart_type` serializes into the
17324/// rendered `Chart.yaml` YAML mapping.
17325///
17326/// The single source of truth every consumer that names the per-
17327/// Chart.yaml top-level per-chart-kind discriminator key reaches for:
17328///
17329///   - [`caixa-helm`][ch]'s `ChartYaml` struct's `chart_type` field
17330///     `#[serde(rename = "type")]` attribute (the sole production
17331///     serialize-side site the literal appears at as a syntactic
17332///     serde-rename argument; the attribute itself cannot consume a
17333///     `const` because Rust's attribute grammar admits only string
17334///     literals, so the discipline here is: the const's byte-shape
17335///     must remain byte-identical to the literal the attribute pins,
17336///     and the drift-detection pin at
17337///     [`caixa-helm`]'s
17338///     `chart_yaml_serializes_type_axis_under_lifted_helm_chart_key_type`
17339///     round-trips a rendered [`caixa-helm`]-emitted `Chart.yaml`
17340///     through `serde_yaml::from_str::<serde_yaml::Value>` and
17341///     asserts the top-level `Mapping::get(HELM_CHART_KEY_TYPE)`
17342///     resolves — closing the drift the syntactic-literal-only
17343///     attribute would otherwise leave silent);
17344///   - every test-side navigator that inspects the serialized
17345///     [`caixa-helm`]-emitted `Chart.yaml` YAML mapping by the top-
17346///     level per-chart-kind discriminator key.
17347///
17348/// A drift on the emitter's serde-rename literal (a future refactor
17349/// that dropped the `#[serde(rename = "type")]` attribute or
17350/// changed the target key to `"Type"` / `"kind"` / `"chartType"`)
17351/// would surface as one of two silent failure modes at
17352/// `helm dependency build` / `helm lint` / `helm template` time
17353/// far from the drift site: the rendered `Chart.yaml`'s top-level
17354/// mapping carries an unrecognized key (`chart_type:` from Rust's
17355/// default snake_case serialization) that Helm's chart-schema
17356/// parser silently ignores, defaulting the per-chart-kind axis to
17357/// `application` with no process-log drift-signal (masking the
17358/// schema-shape violation); or the drift accidentally collapses
17359/// the key onto the sibling `kind` / K8s-CR `KUBE_KEY_KIND`
17360/// axis (byte-distinct today at the substrate — see the paired
17361/// `helm_chart_key_type_is_byte_distinct_from_kube_key_kind` pin)
17362/// that Helm's chart-schema parser silently treats as an unknown
17363/// field, again defaulting the per-chart-kind axis.
17364///
17365/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5)
17366/// promotes the axis-key to a typed substrate-side `&'static str`
17367/// on the same trajectory the peer axis-value lifts
17368/// ([`HELM_CHART_TYPE_APPLICATION`] / [`HELM_CHART_TYPE_LIBRARY`])
17369/// established — completes the per-Chart.yaml per-chart-kind
17370/// discriminator axis single-sourcing at both the key and value
17371/// halves (`{HELM_CHART_KEY_TYPE, HELM_CHART_TYPE_APPLICATION,
17372/// HELM_CHART_TYPE_LIBRARY}`), so the full
17373/// `(key, admitted-value-set)` per-axis lift lives at one canonical
17374/// declaration site. Same "(key, value) axis-pair lift completes at
17375/// one canonical source per half" discipline the peer
17376/// [`KUBE_KEY_API_VERSION`] (7994) + [`HELM_CHART_API_VERSION`]
17377/// (14580) pair carries on the sibling apiVersion axis, and the
17378/// [`FLEET_PROGRAMS_KEY_NAME`] (7651) + `Servico :nome` value pair
17379/// carries on the sibling per-fleet-programs-entry axis.
17380///
17381/// [chart-type-doc]: https://helm.sh/docs/topics/charts/#chart-types
17382/// [ch]: ../../caixa_helm/index.html
17383pub const HELM_CHART_KEY_TYPE: &str = "type";
17384
17385/// Canonical Helm 3 `Chart.yaml` top-level YAML axis-key naming the
17386/// per-chart underlying-application-version field — the load-bearing
17387/// serde-rename literal at [`caixa-helm`][ch]'s `ChartYaml` struct
17388/// (`caixa-helm/src/lib.rs:152`, `#[serde(rename = "appVersion")]`)
17389/// that selects how the Rust field `app_version` serializes into the
17390/// rendered `Chart.yaml` YAML mapping. Distinct from the sibling
17391/// [`Chart.yaml` `version:` field][chart-yaml-desc] (the chart's own
17392/// SemVer, incremented per release of the chart itself); the
17393/// `appVersion:` field the Helm 3 chart-schema pins carries the
17394/// underlying application's version (see [app-version-doc]) — the
17395/// version the containerized workload the chart installs advertises
17396/// (an OCI image tag, a wasm-component `:versao`, a package release
17397/// tag). At the caixa-helm renderer today the two axes both draw
17398/// from the caixa's `:versao` at [`build_chart_yaml`] because a
17399/// [`caixa-core::Caixa`]'s `:versao` names both the chart's own
17400/// release cadence and the underlying wasm-component release
17401/// cadence in one axis (`caixa`'s per-caixa BLAKE3-closure identity
17402/// binds a caixa's chart + wasm-binary + declared source at exactly
17403/// one release axis), but the Chart.yaml schema pins the two YAML
17404/// keys distinctly regardless — every downstream Helm-consumer
17405/// (Artifact Hub's per-chart-search index, `helm search` /
17406/// `helm show chart` operator surfaces) routes the two axes onto
17407/// distinct display fields at chart-inspection time.
17408///
17409/// The single source of truth every consumer that names the per-
17410/// Chart.yaml top-level app-version YAML key reaches for:
17411///
17412///   - [`caixa-helm`][ch]'s `ChartYaml` struct's `app_version` field
17413///     `#[serde(rename = "appVersion")]` attribute (the sole
17414///     production serialize-side site the literal appears at as a
17415///     syntactic serde-rename argument; the same
17416///     attribute-literal-only-grammar constraint the peer
17417///     [`HELM_CHART_KEY_TYPE`] docstring enumerates applies, and
17418///     the paired drift-detection pin at [`caixa-helm`]'s
17419///     `chart_yaml_serializes_app_version_axis_under_lifted_helm_chart_key_app_version`
17420///     round-trips a rendered `Chart.yaml` and asserts the top-level
17421///     `Mapping::get(HELM_CHART_KEY_APP_VERSION)` resolves);
17422///   - every test-side navigator that inspects the serialized
17423///     [`caixa-helm`]-emitted `Chart.yaml` YAML mapping by the top-
17424///     level per-chart-app-version key.
17425///
17426/// A drift on the emitter's serde-rename literal (a future refactor
17427/// that dropped the `#[serde(rename = "appVersion")]` attribute or
17428/// changed the target key to `"AppVersion"` / `"applicationVersion"`
17429/// / `"version"`) would surface as one of two silent failure modes
17430/// at Helm-chart-consumption time far from the drift site: the
17431/// rendered `Chart.yaml`'s top-level mapping carries an unrecognized
17432/// key (`app_version:` from Rust's default snake_case serialization)
17433/// that Helm's chart-schema parser silently drops from the parsed
17434/// chart-metadata shape (masking the schema-shape violation with no
17435/// process-log drift-signal, and every downstream Artifact Hub /
17436/// `helm search` per-chart index falls back to "no application
17437/// version" for the rendered chart); or the drift accidentally
17438/// collapses the app-version key onto the sibling chart-own-version
17439/// `version:` axis (byte-distinct today at the substrate — see the
17440/// paired
17441/// `helm_chart_key_app_version_is_byte_distinct_from_helm_chart_key_version`
17442/// pin) that Helm's chart-schema parser then silently reads under
17443/// the wrong axis, and the chart's own SemVer collides with the
17444/// underlying-application version at every downstream Helm-consumer.
17445///
17446/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5)
17447/// promotes the axis-key to a typed substrate-side `&'static str`
17448/// on the same trajectory the peer [`HELM_CHART_KEY_TYPE`] lift
17449/// established — extends the per-Chart.yaml top-level YAML axis-key
17450/// single-sourcing discipline from the per-chart-kind discriminator
17451/// key onto the sibling per-chart-app-version key, so every
17452/// substrate-side renderer that emits or navigates a `Chart.yaml`
17453/// top-level mapping consults one canonical `&'static str` per axis.
17454///
17455/// [chart-yaml-desc]: https://helm.sh/docs/topics/charts/#the-chartyaml-file
17456/// [app-version-doc]: https://helm.sh/docs/topics/charts/#the-appversion-field
17457/// [ch]: ../../caixa_helm/index.html
17458pub const HELM_CHART_KEY_APP_VERSION: &str = "appVersion";
17459
17460/// Canonical Helm 3 `Chart.yaml` top-level YAML axis-key naming the
17461/// per-chart dependency-list field — the load-bearing serde
17462/// field-name at [`caixa-helm`][ch]'s `ChartYaml` struct's
17463/// `dependencies` field, the parent list-container the already-lifted
17464/// [`HELM_CHART_DEPENDENCY_KEY_NAME`] / [`HELM_CHART_DEPENDENCY_KEY_VERSION`]
17465/// / [`HELM_CHART_DEPENDENCY_KEY_REPOSITORY`] /
17466/// [`HELM_CHART_DEPENDENCY_KEY_ALIAS`] per-entry sub-mapping tetrad
17467/// (69f62db) mounts under. The chart-schema top-level `dependencies:`
17468/// field pins the list of chart-registry references Helm's per-dep
17469/// resolver consults at `helm dependency build` /
17470/// `helm dependency update` time to vendor each dependency chart
17471/// under the substrate's canonical [`DEFAULT_LIBRARY_NAME`] wrap-key
17472/// convention. Every rendered `lareira-<nome>` chart declares exactly
17473/// one entry today (the [`DEFAULT_LIBRARY_NAME`] `pleme-computeunit`
17474/// library-chart dep the sibling [`caixa-helm`][ch]'s `build_chart_yaml`
17475/// mounts) — see [chart-dependencies-doc] for the Helm 3 upstream axis
17476/// documentation.
17477///
17478/// The single source of truth every consumer that names the per-
17479/// Chart.yaml top-level dependency-list key reaches for:
17480///
17481///   - [`caixa-helm`][ch]'s `ChartYaml` struct's `dependencies` field
17482///     (the sole production serialize-side site the wire-key appears
17483///     at — Rust's default field-name-verbatim serde emission means
17484///     no `#[serde(rename = "…")]` attribute pins the key today; the
17485///     paired drift-detection pin at [`caixa-helm`]'s
17486///     `chart_yaml_serializes_dependencies_axis_under_lifted_helm_chart_key_dependencies`
17487///     round-trips a rendered `Chart.yaml` through
17488///     `serde_yaml::from_str::<serde_yaml::Value>` and asserts the
17489///     top-level `Mapping::get(HELM_CHART_KEY_DEPENDENCIES)` resolves —
17490///     closing the drift a future hostile refactor could otherwise
17491///     leave silent: a rename of the Rust field to `Vec<ChartDependency>
17492///     under a `deps:` / `chartDependencies:` name, or an accidental
17493///     `#[serde(rename_all = "camelCase")]` attribute on `ChartYaml`
17494///     that stays a no-op on the four identity-mapped top-level keys
17495///     today but silently activates on a future multi-word field
17496///     addition);
17497///   - every test-side navigator that inspects the serialized
17498///     [`caixa-helm`]-emitted `Chart.yaml` YAML mapping by the top-
17499///     level per-chart-dependency-list key.
17500///
17501/// A drift on this per-Chart.yaml top-level list-container axis-key
17502/// would silently rebrand the wire key — Helm's chart-schema parser
17503/// silently drops the dep list from the parsed chart-metadata shape,
17504/// `helm dependency build` finds no chart to vendor, and every
17505/// rendered `lareira-<nome>` chart's install fails with
17506/// `template: no template ... associated with template ...` far from
17507/// the drift site with no field naming the top-level-list-key-drift
17508/// root cause. The failure mode is byte-shape-symmetric with the peer
17509/// [`HELM_CHART_DEPENDENCY_KEY_NAME`] drift narrative (which closes on
17510/// the per-entry name axis one level down) — both close on the
17511/// `helm dependency build` / apply-time path.
17512///
17513/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5)
17514/// promotes the top-level list-container axis-key to a typed
17515/// substrate-side `&'static str` on the same trajectory the peer
17516/// [`HELM_CHART_KEY_TYPE`] / [`HELM_CHART_KEY_APP_VERSION`] /
17517/// [`HELM_CHART_KEY_API_VERSION`] top-level axis-key lifts (d29bc23,
17518/// cc44e4b) established — completes the parent+children canonical-pin
17519/// pair with the already-lifted per-`dependencies[]`-entry
17520/// sub-mapping tetrad. Where the child tetrad pins the byte-shape of
17521/// each per-dep entry's four sub-mapping keys (`name`, `version`,
17522/// `repository`, `alias`), this parent-axis lift pins the byte-shape
17523/// of the top-level list-container the tetrad mounts under, so the
17524/// full `(dependencies: → [name/version/repository/alias])`
17525/// per-Chart.yaml dependency-list schema surface lives at one
17526/// canonical `&'static str` per YAML axis-key. Same
17527/// "parent list-container + child sub-mapping tetrad" canonical-pin
17528/// discipline the peer [`SUPERVISOR_KEY_CHILDREN`] (parent) +
17529/// [`SUPERVISOR_CHILD_KEY_CAIXA`] / [`SUPERVISOR_CHILD_KEY_VERSAO`] /
17530/// [`SUPERVISOR_CHILD_KEY_RESTART`] (children) pair (40cc4e5, ef912df)
17531/// established on the sibling per-`:supervisor :children` axis, and the
17532/// peer [`M2_KEY_UPGRADE_FROM`] (parent) +
17533/// [`M2_UPGRADE_FROM_KEY_FROM`] / [`M2_UPGRADE_FROM_KEY_INSTRUCTIONS`]
17534/// (children) pair established on the sibling per-`:upgrade-from` axis.
17535///
17536/// [chart-yaml-desc]: https://helm.sh/docs/topics/charts/#the-chartyaml-file
17537/// [chart-dependencies-doc]: https://helm.sh/docs/topics/charts/#chart-dependencies
17538/// [ch]: ../../caixa_helm/index.html
17539pub const HELM_CHART_KEY_DEPENDENCIES: &str = "dependencies";
17540
17541/// Canonical Helm 3 `Chart.yaml` per-`dependencies[]`-entry sub-mapping
17542/// YAML axis-key naming the per-dep chart-name field — the load-bearing
17543/// serde field-name at [`caixa-helm`][ch]'s `ChartDependency` struct's
17544/// `name` field. Byte-identical to the sibling K8s CR
17545/// [`KUBE_KEY_NAME`] axis-key by Helm's design decision to inherit the
17546/// K8s CR body-key vocabulary at every schema surface it consumes
17547/// (chart-metadata, per-CR install-payload, per-dep dependency-list);
17548/// the paired
17549/// [`tests::helm_chart_dependency_key_name_matches_kube_key_name`] pin
17550/// asserts the two byte-shapes coincide, so a future K8s-side rebrand
17551/// at [`KUBE_KEY_NAME`] that dropped the byte-identity would fail the
17552/// pin at substrate-build time rather than silently drop the per-dep
17553/// name lookup at `helm dependency build` time far from the drift site.
17554///
17555/// The chart-schema per-dep entry's `name:` value pins the exact
17556/// Helm-registry chart-name Helm's per-dep alias convention scopes the
17557/// per-dep values sub-block under when no `alias:` is set (see the
17558/// sibling [`HELM_CHART_DEPENDENCY_KEY_ALIAS`] docstring for the alias
17559/// axis) — every rendered `lareira-<nome>` chart's Chart.yaml
17560/// `dependencies[0].name:` binds to the same `&'static str` as its
17561/// values.yaml wrap key (see [`caixa-helm`][ch]'s
17562/// `values_yaml_wrap_key_matches_chart_dependency_name` pin on the
17563/// structural alignment). A drift on this per-dep sub-key (a future
17564/// refactor that renamed the `ChartDependency::name` Rust field to
17565/// `ChartDependency::nome`, or added a
17566/// `#[serde(rename_all = "camelCase")]` attribute that stays a no-op
17567/// on the four identity-mapped keys today but silently activates on a
17568/// future field addition) would rebrand the wire key silently — Helm's
17569/// per-dep dependency-router silently drops the dep from the parsed
17570/// chart-metadata (the substrate ships a Chart.yaml that lists no
17571/// `pleme-computeunit` dep, `helm dependency build` finds no chart to
17572/// vendor, and every rendered lareira-`<nome>` chart's install fails
17573/// with "template: no template ... associated with template ..." far
17574/// from the drift site). Peer to [`HELM_CHART_DEPENDENCY_KEY_VERSION`]
17575/// / [`HELM_CHART_DEPENDENCY_KEY_REPOSITORY`] /
17576/// [`HELM_CHART_DEPENDENCY_KEY_ALIAS`] on the sibling per-dep sub-key
17577/// axes — completes the per-`dependencies[]`-entry YAML axis-key
17578/// canonical-pin tetrad at the substrate. Same per-entry-sub-key
17579/// canonical-lift discipline the peer
17580/// [`SUPERVISOR_CHILD_KEY_CAIXA`] / [`SUPERVISOR_CHILD_KEY_VERSAO`] /
17581/// [`SUPERVISOR_CHILD_KEY_RESTART`] triad (ef912df) established on the
17582/// sibling per-`:children` sub-mapping surface, and the
17583/// [`ENTRADA_KEY_HOST`] / [`ENTRADA_KEY_PARA`] / [`ENTRADA_KEY_PATHS`]
17584/// / [`ENTRADA_KEY_PORT`] tetrad (a3d6162) established on the sibling
17585/// per-`:entrada` sub-mapping surface.
17586///
17587/// [ch]: ../../caixa_helm/index.html
17588pub const HELM_CHART_DEPENDENCY_KEY_NAME: &str = "name";
17589
17590/// Canonical Helm 3 `Chart.yaml` per-`dependencies[]`-entry sub-mapping
17591/// YAML axis-key naming the per-dep chart-version-constraint field —
17592/// the load-bearing serde field-name at [`caixa-helm`][ch]'s
17593/// `ChartDependency` struct's `version` field. Distinct from the
17594/// sibling per-Chart.yaml top-level chart-own-SemVer axis-key
17595/// (`version:` at the top level, whose byte-shape coincides with this
17596/// per-dep sub-key at the wire — a coincidence the substrate-side
17597/// paired [`tests::helm_chart_dependency_key_version_pins_canonical_value`]
17598/// pin holds byte-verbatim). The chart-schema per-dep entry's
17599/// `version:` value pins the SemVer-range constraint Helm's per-dep
17600/// resolver matches against the target dep's Chart.yaml `version:`
17601/// scalar at `helm dependency build` / `helm dependency update` time.
17602/// A drift on this per-dep sub-key would surface as one of two silent
17603/// failure modes at chart-vendor time far from the drift site: Helm's
17604/// per-dep chart-schema parser silently drops the version-constraint
17605/// scalar from the parsed dep-entry (the per-dep resolver falls back
17606/// to the wildcard `*` shape and vendors whatever chart-version the
17607/// upstream registry currently advertises, silently promoting a chart
17608/// upgrade the operator never authored), or a subsequent
17609/// `#[serde(rename_all)]` addition rebrands the key to Helm's
17610/// unrecognized shape and the per-dep entry silently vanishes from the
17611/// parsed dep-list. Peer to [`HELM_CHART_DEPENDENCY_KEY_NAME`] /
17612/// [`HELM_CHART_DEPENDENCY_KEY_REPOSITORY`] /
17613/// [`HELM_CHART_DEPENDENCY_KEY_ALIAS`] on the sibling per-dep sub-key
17614/// axes — extends the per-entry-sub-key canonical-lift tetrad at the
17615/// substrate. See [`HELM_CHART_DEPENDENCY_KEY_NAME`] for the shared
17616/// per-entry-sub-mapping lift rationale.
17617///
17618/// [ch]: ../../caixa_helm/index.html
17619pub const HELM_CHART_DEPENDENCY_KEY_VERSION: &str = "version";
17620
17621/// Canonical Helm 3 `Chart.yaml` per-`dependencies[]`-entry sub-mapping
17622/// YAML axis-key naming the per-dep chart-registry URL field — the
17623/// load-bearing serde field-name at [`caixa-helm`][ch]'s
17624/// `ChartDependency` struct's `repository` field. The chart-schema
17625/// per-dep entry's `repository:` value pins the Helm-registry URL
17626/// (`file://…`, `https://…`, `oci://…`) Helm's per-dep resolver
17627/// consults at `helm dependency build` time to fetch the per-dep
17628/// chart bytes. At the caixa-helm substrate the default value is the
17629/// canonical [`caixa_helm::DEFAULT_LIBRARY_REPO`] pointing at the
17630/// helmworks file:// path; the future per-edition library-chart
17631/// re-emission for the OCI registry (once `pleme-io/helmworks/charts`
17632/// lands as an OCI-registry-backed chart-source) reaches this axis
17633/// through a paired scalar-value lift on the per-dep repo axis. A
17634/// drift on this per-dep sub-key would surface as one of two silent
17635/// failure modes at chart-vendor time far from the drift site: Helm's
17636/// per-dep resolver silently drops the repository scalar from the
17637/// parsed dep-entry (the per-dep resolver falls back to the "no
17638/// repository set" shape and refuses to vendor the dep with
17639/// `no repository defined`), or the per-dep chart-schema parser
17640/// silently absorbs a rename drift via `#[serde(default)]`
17641/// fall-through at the struct-side and the per-dep repo axis lands
17642/// under Rust's `""` default — Helm rejects the empty URL at
17643/// `helm dependency build` time. Peer to
17644/// [`HELM_CHART_DEPENDENCY_KEY_NAME`] /
17645/// [`HELM_CHART_DEPENDENCY_KEY_VERSION`] /
17646/// [`HELM_CHART_DEPENDENCY_KEY_ALIAS`] on the sibling per-dep sub-key
17647/// axes. See [`HELM_CHART_DEPENDENCY_KEY_NAME`] for the shared
17648/// per-entry-sub-mapping lift rationale.
17649///
17650/// [ch]: ../../caixa_helm/index.html
17651pub const HELM_CHART_DEPENDENCY_KEY_REPOSITORY: &str = "repository";
17652
17653/// Canonical Helm 3 `Chart.yaml` per-`dependencies[]`-entry sub-mapping
17654/// YAML axis-key naming the per-dep chart-alias override field — the
17655/// load-bearing serde field-name at [`caixa-helm`][ch]'s
17656/// `ChartDependency` struct's `alias` field. The chart-schema per-dep
17657/// entry's `alias:` value, when set, overrides the per-dep values
17658/// wrap-key (Helm's per-dep alias convention scopes the per-dep values
17659/// sub-block under `alias:` when set, and under the sibling
17660/// [`HELM_CHART_DEPENDENCY_KEY_NAME`] `name:` value otherwise); the
17661/// caixa-helm substrate today emits the axis as `None` at every
17662/// rendered `lareira-<nome>` chart's `dependencies[0].alias:` (the
17663/// `#[serde(default, skip_serializing_if = "Option::is_none")]`
17664/// attribute on the `alias` field elides the axis entirely from the
17665/// emitted YAML when unset), so the values wrap-key defaults to the
17666/// per-dep `name:` value — but the axis-key remains part of the
17667/// substrate-side chart-schema-per-dep-entry contract for the future
17668/// per-Aplicacao library chart's per-Servico per-dep aliasing
17669/// [`HELM_CHART_TYPE_LIBRARY`] docstring names as a trajectory item.
17670/// A drift on this per-dep sub-key (a future refactor that renamed
17671/// the `ChartDependency::alias` Rust field, or added a
17672/// `#[serde(rename_all = "camelCase")]` attribute that silently
17673/// activates on a future field addition) would rebrand the wire key
17674/// silently — Helm's per-dep alias-convention router would silently
17675/// drop the alias from the parsed dep-entry (the per-dep values wrap-
17676/// key falls back to the sibling `name:` value, and every per-cluster
17677/// per-Servico per-dep values override the operator authored under
17678/// the alias-key silently routes nowhere at `helm template` time). Peer
17679/// to [`HELM_CHART_DEPENDENCY_KEY_NAME`] /
17680/// [`HELM_CHART_DEPENDENCY_KEY_VERSION`] /
17681/// [`HELM_CHART_DEPENDENCY_KEY_REPOSITORY`] on the sibling per-dep
17682/// sub-key axes — completes the per-`dependencies[]`-entry YAML
17683/// axis-key canonical-pin tetrad. See [`HELM_CHART_DEPENDENCY_KEY_NAME`]
17684/// for the shared per-entry-sub-mapping lift rationale.
17685///
17686/// [ch]: ../../caixa_helm/index.html
17687pub const HELM_CHART_DEPENDENCY_KEY_ALIAS: &str = "alias";
17688
17689/// Canonical Helm 3 per-chart-directory metadata-file filename every
17690/// rendered `lareira-<nome>` chart carries at its top-level directory —
17691/// the fixed filename Helm's chart-schema parser (`helm dependency
17692/// build`, `helm lint`, `helm template`, `helm install`) looks up by
17693/// name at the chart-directory root to locate the per-chart
17694/// [`HELM_CHART_API_VERSION`] + [`HELM_CHART_TYPE_APPLICATION`] +
17695/// name/version/dependencies scalars each `lareira-<nome>` chart
17696/// declares (see [chart-yaml-desc]). The single source of truth every
17697/// consumer that names the metadata file — the sole caixa-helm
17698/// production emit site the prior inline `"Chart.yaml"` literal sat at
17699/// ([`caixa-helm`][ch]'s [`render_chart_for_servico`][rcs] `ChartDir`
17700/// assembly's per-file `path` axis, one of the three canonical
17701/// `lareira-<nome>` chart-directory files the renderer emits as a
17702/// bundle) plus every test-side round-trip navigator that reaches into
17703/// the rendered `ChartDir` by the metadata filename (six sites across
17704/// [`caixa-helm`][ch]'s per-chart-metadata-field sweep tests +
17705/// [`ChartDir::write_to`] post-write existence pin) — reaches for the
17706/// same `&'static str` by construction.
17707///
17708/// Until this lift landed the filename `"Chart.yaml"` lived as seven
17709/// verbatim inline literals (one production `PathBuf::from("Chart.yaml")`
17710/// at the `ChartDir` files-vec construction site + six test-side
17711/// `PathBuf::from("Chart.yaml")` / `chart_root.join("Chart.yaml")` /
17712/// `names.contains(&"Chart.yaml".to_string())` fixture navigators).
17713/// A drift on the emit side (a `"chart.yaml"` / `"chart.YAML"` /
17714/// `"Chart.yml"` / `"chart.yaml.tmpl"` typo, or an accidental collapse
17715/// onto Helm 2's sibling per-chart-metadata-filename axis, or a
17716/// per-fork `Chartfile.yaml` rebrand any per-edition packaging
17717/// substrate might introduce) at any one site would surface as one of
17718/// two silent failure modes at chart-consumption time:
17719///
17720///   - Helm's chart-schema parser refuses to open the rendered chart-
17721///     directory as a chart at all — `helm lint` / `helm dependency
17722///     build` fails with "Error: Chart.yaml file is missing" far from
17723///     the emit-drift commit's source, and the per-Servico release
17724///     cycle drops with no field naming the metadata-filename-drift
17725///     root cause (the operator sees "the chart isn't being recognized"
17726///     with no canonical anchor to compare the rendered filename
17727///     against);
17728///   - the rendered chart's `ChartFile` collection lists a file at the
17729///     emit-side drifted name (e.g. `"chart.yaml"`) while the sibling
17730///     [`caixa-flux`][cf] `Kustomization` bundle-path emitter's per-
17731///     chart reference (a future per-cluster snapshot bundle that
17732///     re-lists the chart-dir contents by filename) continues to look
17733///     under the canonical `"Chart.yaml"` — the two-crate pair silently
17734///     goes out of sync, with the flux bundle's chart-directory
17735///     resolver returning `None` for the metadata file at cluster-side
17736///     `feira app deploy` time.
17737///
17738/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
17739/// "every recurring shape becomes a generator before it becomes a
17740/// pattern; every pattern becomes a library before it becomes
17741/// duplicated code. The duplication budget is zero.") promotes the
17742/// filename to a typed substrate-side `&'static str` on the same
17743/// trajectory the peer [`HELM_CHART_API_VERSION`] /
17744/// [`HELM_CHART_TYPE_APPLICATION`] / [`DEFAULT_LIBRARY_NAME`] /
17745/// [`LAREIRA_CHART_NAME_PREFIX`] lifts established on the sibling
17746/// canonical-Helm-load-bearing-string axes — pivots the discipline
17747/// from the per-Chart.yaml top-level *body* axes (`apiVersion`,
17748/// `type`) onto the sibling per-chart-directory *filename* axis every
17749/// rendered chart directory carries as the fixed lookup name Helm's
17750/// chart-schema parser consults at chart-open time. Peer to the
17751/// canonical-Helm-chart-schema-axis lifts on the sibling per-Chart.yaml
17752/// body surfaces — completes the per-`lareira-<nome>`-chart-directory
17753/// `(filename, apiVersion, type)` canonical-scalar-axis re-export triple
17754/// every rendered chart declares at its top-level metadata file.
17755///
17756/// [chart-yaml-desc]: https://helm.sh/docs/topics/charts/#the-chartyaml-file
17757/// [ch]: ../../caixa_helm/index.html
17758/// [cf]: ../../caixa_flux/index.html
17759/// [rcs]: ../../caixa_helm/fn.render_chart_for_servico.html
17760pub const HELM_CHART_YAML_FILENAME: &str = "Chart.yaml";
17761
17762/// Canonical Helm 3 per-chart-directory values-file filename every
17763/// rendered `lareira-<nome>` chart carries at its top-level directory —
17764/// the fixed filename Helm's chart-schema parser (`helm dependency
17765/// build`, `helm lint`, `helm template`, `helm install`) looks up by
17766/// name at the chart-directory root to locate the per-chart
17767/// [`DEFAULT_LIBRARY_NAME`]-wrapped values block that
17768/// [`HELM_VALUES_KEY_ENABLED`] toggles (see [values-yaml-desc]). The
17769/// single source of truth every consumer that names the values file —
17770/// the sole caixa-helm production emit site the prior inline
17771/// `"values.yaml"` literal sat at ([`caixa-helm`][ch]'s
17772/// [`render_chart_for_servico`][rcs] `ChartDir` assembly's per-file
17773/// `path` axis, the second of the three canonical `lareira-<nome>`
17774/// chart-directory files the renderer emits as a bundle, sibling to
17775/// the metadata-file [`HELM_CHART_YAML_FILENAME`] axis) plus every
17776/// test-side round-trip navigator that reaches into the rendered
17777/// `ChartDir` by the values filename (eleven sites across
17778/// [`caixa-helm`][ch]'s per-chart-values-field sweep tests +
17779/// [`ChartDir::write_to`] post-write existence pin) — reaches for the
17780/// same `&'static str` by construction.
17781///
17782/// Until this lift landed the filename `"values.yaml"` lived as twelve
17783/// verbatim inline literals (one production `PathBuf::from("values.yaml")`
17784/// at the `ChartDir` files-vec construction site + eleven test-side
17785/// `PathBuf::from("values.yaml")` / `chart_root.join("values.yaml")` /
17786/// `names.contains(&"values.yaml".to_string())` fixture navigators).
17787/// A drift on the emit side (a `"Values.yaml"` / `"values.YAML"` /
17788/// `"values.yml"` / `"values.yaml.tmpl"` typo, or an accidental collapse
17789/// onto Helm 2's sibling per-chart-values-filename axis, or a per-fork
17790/// `defaults.yaml` rebrand any per-edition packaging substrate might
17791/// introduce) at any one site would surface as one of two silent
17792/// failure modes at chart-consumption time:
17793///
17794///   - Helm's per-chart values-loader silently falls back to the empty
17795///     values block — `helm template` / `helm install` emits the
17796///     `pleme-computeunit` library chart under its admission-time
17797///     defaults (`enabled: false`, no per-`:limits` / `:behavior` /
17798///     `:upgrade-from` M2 overlay), the workload silently comes up
17799///     disabled or without any per-Servico M2 overlay applied, and
17800///     the per-Servico release cycle drops with no field naming the
17801///     values-filename-drift root cause (the operator sees "the
17802///     Servico isn't doing what we configured it to do" with no
17803///     canonical anchor to compare the rendered filename against);
17804///   - the rendered chart's `ChartFile` collection lists a file at the
17805///     emit-side drifted name (e.g. `"Values.yaml"`) while the sibling
17806///     [`caixa-flux`][cf] `Kustomization` bundle-path emitter's per-
17807///     chart reference (a future per-cluster snapshot bundle that
17808///     re-lists the chart-dir contents by filename to route per-cluster
17809///     values overlays through the canonical values file) continues to
17810///     look under the canonical `"values.yaml"` — the two-crate pair
17811///     silently goes out of sync, with the flux bundle's chart-directory
17812///     resolver returning `None` for the values file at cluster-side
17813///     `feira app deploy` time, and every per-cluster overlay the
17814///     bundle path threads through silently drops.
17815///
17816/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
17817/// "every recurring shape becomes a generator before it becomes a
17818/// pattern; every pattern becomes a library before it becomes
17819/// duplicated code. The duplication budget is zero.") promotes the
17820/// filename to a typed substrate-side `&'static str` on the same
17821/// trajectory the peer [`HELM_CHART_YAML_FILENAME`] (c2c99b0) /
17822/// [`HELM_CHART_API_VERSION`] / [`HELM_CHART_TYPE_APPLICATION`] /
17823/// [`HELM_VALUES_KEY_ENABLED`] / [`DEFAULT_LIBRARY_NAME`] /
17824/// [`LAREIRA_CHART_NAME_PREFIX`] lifts established on the sibling
17825/// canonical-Helm-load-bearing-string axes — pivots the discipline
17826/// from the metadata-file half of the `(Chart.yaml, values.yaml)`
17827/// canonical per-chart-directory filename pair onto the values-file
17828/// half, completing the per-`lareira-<nome>`-chart-directory
17829/// canonical-scalar-axis re-export triple every rendered chart declares
17830/// as its `ChartDir::files` entries (`{Chart.yaml, values.yaml,
17831/// README.md}` — the two schema-load-bearing filenames now share the
17832/// same substrate-side single-source discipline).
17833///
17834/// [values-yaml-desc]: https://helm.sh/docs/chart_template_guide/values_files/
17835/// [ch]: ../../caixa_helm/index.html
17836/// [cf]: ../../caixa_flux/index.html
17837/// [rcs]: ../../caixa_helm/fn.render_chart_for_servico.html
17838pub const HELM_VALUES_YAML_FILENAME: &str = "values.yaml";
17839
17840/// Canonical `lareira-<nome>` chart-directory human-facing readme filename
17841/// every rendered chart carries at its top-level directory — the fixed
17842/// filename the `caixa-helm` renderer emits alongside the two schema-load-
17843/// bearing [`HELM_CHART_YAML_FILENAME`] + [`HELM_VALUES_YAML_FILENAME`]
17844/// files as the third leg of the canonical `{Chart.yaml, values.yaml,
17845/// README.md}` per-`lareira-<nome>` chart-directory `ChartFile` triple the
17846/// peer [`HELM_CHART_YAML_FILENAME`] docstring explicitly acknowledges is
17847/// the one axis where the substrate-side single-source discipline had not
17848/// yet landed at the third file. The single source of truth every
17849/// consumer that names the readme file — the sole caixa-helm production
17850/// emit site the prior inline `"README.md"` literal sat at
17851/// ([`caixa-helm`][ch]'s [`render_chart_for_servico`][rcs] `ChartDir`
17852/// assembly's per-file `path` axis, the third of the three canonical
17853/// `lareira-<nome>` chart-directory files the renderer emits as a bundle,
17854/// sibling to the metadata-file [`HELM_CHART_YAML_FILENAME`] +
17855/// values-file [`HELM_VALUES_YAML_FILENAME`] axes) plus every test-side
17856/// round-trip navigator that reaches into the rendered `ChartDir` by the
17857/// readme filename (two sites: the `renders_three_files` files-vec-
17858/// membership pin + the `ChartDir::write_to` post-write existence pin) —
17859/// reaches for the same `&'static str` by construction.
17860///
17861/// Until this lift landed the filename `"README.md"` lived as three
17862/// verbatim inline literals (one production `ChartFile::new("README.md",
17863/// …)` at the `ChartDir` files-vec construction site + two test-side
17864/// `names.contains(&"README.md".to_string())` / `chart_root.join("README.md")`
17865/// fixture navigators). A drift on the emit side (a `"readme.md"` /
17866/// `"Readme.md"` / `"README"` / `"README.MD"` typo, or an accidental
17867/// collapse onto the sibling per-workspace `readme.txt` axis any
17868/// per-edition packaging substrate might introduce) at any one site would
17869/// surface as one of two silent failure modes at chart-consumption time:
17870///
17871///   - GitHub / Artifact Hub / any downstream per-chart README-surfacing
17872///     UI silently falls back to "no README available" — the chart lists
17873///     with no per-chart elevator pitch or install instructions far from
17874///     the drift commit's source, and the operator sees a chart in the
17875///     hub without the canonical `## Install` block the emitter wrote,
17876///     with no field naming the readme-filename-drift root cause;
17877///   - the rendered chart's `ChartFile` collection lists a file at the
17878///     emit-side drifted name (e.g. `"readme.md"`) while the sibling
17879///     [`caixa-flux`][cf] `Kustomization` bundle-path emitter's future
17880///     per-chart-directory resolver — a per-cluster snapshot bundle that
17881///     re-lists the chart-dir contents by filename to surface the
17882///     canonical README to per-cluster tooling — continues to look under
17883///     the canonical `"README.md"` — the two-crate pair silently goes out
17884///     of sync, with the flux bundle's chart-directory resolver returning
17885///     `None` for the readme file at cluster-side `feira app deploy`
17886///     time, and every downstream README-consuming path silently drops.
17887///
17888/// The PRIME DIRECTIVE duplication-budget rule (THEORY.md §I.3.5,
17889/// "every recurring shape becomes a generator before it becomes a
17890/// pattern; every pattern becomes a library before it becomes
17891/// duplicated code. The duplication budget is zero.") promotes the
17892/// filename to a typed substrate-side `&'static str` on the same
17893/// trajectory the peer [`HELM_CHART_YAML_FILENAME`] (c2c99b0) /
17894/// [`HELM_VALUES_YAML_FILENAME`] (9a980ba) lifts established on the
17895/// sibling canonical-Helm-per-chart-directory-filename axes — pivots the
17896/// discipline from the two schema-load-bearing filename halves onto the
17897/// human-facing readme-file half, completing the per-`lareira-<nome>`-
17898/// chart-directory `(Chart.yaml, values.yaml, README.md)` canonical-per-
17899/// chart-directory-filename-axis re-export triple every rendered chart
17900/// declares as its three `ChartDir::files` entries — the third file the
17901/// peer [`HELM_VALUES_YAML_FILENAME`] docstring explicitly names as the
17902/// missing leg of the triple at its "completing the per-`lareira-<nome>`-
17903/// chart-directory canonical-scalar-axis re-export triple every rendered
17904/// chart declares as its `ChartDir::files` entries (`{Chart.yaml,
17905/// values.yaml, README.md}` — the two schema-load-bearing filenames now
17906/// share the same substrate-side single-source discipline)" close.
17907///
17908/// [ch]: ../../caixa_helm/index.html
17909/// [cf]: ../../caixa_flux/index.html
17910/// [rcs]: ../../caixa_helm/fn.render_chart_for_servico.html
17911pub const HELM_CHART_README_FILENAME: &str = "README.md";
17912
17913/// Canonical `pleme-computeunit` library-chart values-block enable-toggle
17914/// key — the `enabled: <bool>` axis every `lareira-<nome>` chart's values
17915/// block carries under its [`DEFAULT_LIBRARY_NAME`] wrap key, and every
17916/// [`caixa-flux`][cf]-rendered `HelmRelease` `spec.values.<library>.enabled`
17917/// per-cluster override targets. The single source of truth all four
17918/// downstream consumers reach for:
17919///
17920///   - [`caixa-helm`][ch]'s [`build_values_yaml`][bvy] inserts
17921///     `enabled: <opts.enabled_default>` under the values wrap key
17922///     (caixa-helm/src/lib.rs:389) — the rendered `values.yaml`'s
17923///     default-off toggle a cluster operator flips on per environment;
17924///   - [`caixa-flux`][cf]'s [`cluster_bundle`][cb] emits
17925///     `<library>: { enabled: true }` under the `HelmRelease`
17926///     `spec.values` block (caixa-flux/src/lib.rs:844) — the per-cluster
17927///     override the bundle path threads through so a Servico deployed via
17928///     the bundle path lands enabled at the target cluster;
17929///   - the peer test-fixture navigators in both crates
17930///     (`caixa-helm/src/lib.rs:566, 616` sweeping the default-off arm +
17931///     `caixa-flux/src/lib.rs:1889` sweeping the bundle-path enabled-true
17932///     override arm) resolve the same `&'static str` when parsing back the
17933///     rendered `values.yaml` / `helmrelease.yaml` to pin the round-trip;
17934///   - every future per-Servico renderer the absorption-roadmap
17935///     acknowledges (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
17936///     materializer's per-member values fan-out, a future per-cluster
17937///     values overlay emitter, a future per-edition `<lib>-computeunit`
17938///     values-block schema fork) that reads or emits the same values-
17939///     block-toggle key.
17940///
17941/// Until this lift landed the value `"enabled"` lived as two production-
17942/// code call sites (caixa-helm's `build_values_yaml` insert +
17943/// caixa-flux's `cluster_bundle` `helmrelease.yaml` format-string) plus
17944/// three test-fixture-navigation sites (caixa-helm's default-off round-
17945/// trip + caixa-flux's bundle-path round-trip). A future rebrand of the
17946/// library-chart's per-values enable-toggle axis (the `pleme-computeunit`
17947/// library chart moving to a `chart.enabled` / `spec.enabled` scoping to
17948/// leave room for a sibling `component.enabled` sub-chart toggle, the
17949/// substrate forking the library chart to `<edition>-computeunit` with a
17950/// migrated toggle key, or Helm's own per-values-block convention drift)
17951/// without a coordinated edit on both consumers would silently emit a
17952/// chart whose default-off toggle lands in the values block under one key
17953/// while the cluster-side override lands under another — Helm's per-values
17954/// merge treats them as sibling scalars, the enable-toggle the library
17955/// chart's own template consults never sees the flip, and the workload
17956/// silently comes up with the library chart's admission-time defaults
17957/// (disabled, or the sibling schema fork's own default) instead of the
17958/// per-cluster override the operator set. The apply-time symptom (the
17959/// workload is registered but not running, or is running without the
17960/// per-cluster overlay) surfaces only as "the service isn't doing what we
17961/// configured it to do" far from the rebrand commit, with no field
17962/// naming the enable-toggle-drift root cause. Lifting the literal to
17963/// a shared constant closes the drift footgun structurally — both
17964/// production emit sites and every test-side round-trip navigator now
17965/// consult the same `&'static str`, so any rebrand reaches every consumer
17966/// by construction.
17967///
17968/// Same "the typed constant lives in one place" discipline the peer
17969/// [`DEFAULT_LIBRARY_NAME`] (41438dc) / [`HELM_CHART_API_VERSION`]
17970/// (7e4bdb8) / [`KUBE_KEY_SPEC`] lifts apply on the sibling canonical-
17971/// Helm-load-bearing-string / canonical-Helm-chart-schema-axis /
17972/// canonical-K8s-CR-body-axis surfaces — extends the discipline from
17973/// the Chart.yaml schema axes and the K8s CR body axes onto the Helm
17974/// values-block schema axis nested inside every `lareira-<nome>` chart
17975/// under its [`DEFAULT_LIBRARY_NAME`] wrap key.
17976///
17977/// [ch]: ../../caixa_helm/index.html
17978/// [cf]: ../../caixa_flux/index.html
17979/// [bvy]: ../../caixa_helm/fn.build_values_yaml.html
17980/// [cb]: ../../caixa_flux/fn.cluster_bundle.html
17981pub const HELM_VALUES_KEY_ENABLED: &str = "enabled";
17982
17983/// Canonical Helm chart-name prefix for every per-Servico chart the
17984/// substrate emits — the `"lareira-"` segment of the well-known
17985/// `lareira-<nome>` shape every caixa Servico renderer prepends to a
17986/// caixa's `:nome` to derive its [`Chart.yaml` `name:`][chart-yaml] field,
17987/// its OCI artifact reference (`oci://<registry>/lareira-<nome>`), and
17988/// the resulting cluster-side `HelmRelease` `release_name`. The single
17989/// source of truth all three downstream Servico renderers consult —
17990/// [`caixa-helm`][cf]'s `render_chart_for_servico` chart-dir name
17991/// (caixa-helm/src/lib.rs:207), [`caixa-flux`][cm]'s `cluster_bundle`
17992/// `HelmRelease` `chart:` field (caixa-flux/src/lib.rs:329), and
17993/// [`caixa-tatara`][ct]'s `process_for_aplicacao` `release_name` +
17994/// `derive_chart_ref` OCI ref (caixa-tatara/src/lib.rs:124,182) — so a
17995/// future per-chart-name-prefix rebrand (e.g. moving to `forno-` once
17996/// `lareira-` outlives its scoping intent, or any segment-namespace
17997/// migration the chart-publishing pipeline requires) is a one-line edit
17998/// here, not a coordinated rewrite across every renderer crate's chart-
17999/// name-derivation site.
18000///
18001/// Until this lift landed all three renderers carried inline
18002/// `format!("lareira-{}", caixa.nome)` / `format!("lareira-{name}")` /
18003/// `format!("oci://{}/lareira-{}", registry, caixa.nome.as_str())`
18004/// expressions — three verbatim copies of the same substrate-wide
18005/// naming convention. The PRIME DIRECTIVE duplication budget of zero
18006/// (THEORY.md §I.3.5) lands the lift here at the third occurrence: a
18007/// future rebrand on any one site without a coordinated edit on the
18008/// others would have silently published a chart at one name, registered
18009/// its OCI ref at a second, and resolved the `HelmRelease` at a third —
18010/// the cluster's apply would surface as a `chart pull failed: image not
18011/// found` error far from the source rebrand commit, with no field
18012/// naming the prefix-drift root cause.
18013///
18014/// Lifting it to caixa-core's render-constants block alongside the peer
18015/// [`DEFAULT_NAMESPACE`] (a085b26) makes the chart-name-prefix axis
18016/// discipline structural: every renderer that derives a per-Servico
18017/// chart name consults [`lareira_chart_name`], and every future renderer
18018/// (the future per-cluster snapshot bundle emitter, the future M4
18019/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's chart-ref slot,
18020/// the future caixa-otel collector chart name) inherits the same prefix
18021/// by construction, with no opportunity for per-renderer drift. Same
18022/// "the typed constant lives in one place" discipline the
18023/// [`PLEME_LABEL_PREFIX`] / [`DEFAULT_NAMESPACE`] / [`KUBE_KEY_API_VERSION`]
18024/// lifts apply on the peer shared-string axes.
18025///
18026/// [chart-yaml]: https://helm.sh/docs/topics/charts/#the-chartyaml-file
18027/// [cf]: ../../caixa_helm/index.html
18028/// [cm]: ../../caixa_flux/index.html
18029/// [ct]: ../../caixa_tatara/index.html
18030pub const LAREIRA_CHART_NAME_PREFIX: &str = "lareira-";
18031
18032/// Derive the canonical per-Servico Helm chart name from a caixa's
18033/// `:nome` — the substrate-wide `lareira-<nome>` shape every
18034/// per-Servico renderer ([`caixa-helm`][cf]'s `render_chart_for_servico`
18035/// chart-dir name, [`caixa-flux`][cm]'s `cluster_bundle` `HelmRelease`
18036/// `chart:` field, [`caixa-tatara`][ct]'s `process_for_aplicacao`
18037/// `release_name`, and the `oci://<registry>/lareira-<nome>` OCI ref)
18038/// composes by prepending [`LAREIRA_CHART_NAME_PREFIX`].
18039///
18040/// Single source of truth for the prefix-application: every consumer
18041/// reaches for this helper rather than re-deriving the `format!(…)`
18042/// shape inline, so a future change to the prefix axis (the lift's
18043/// raison d'être) is one edit here, not a coordinated sweep across
18044/// every renderer.
18045///
18046/// The input `nome` is the caixa's typed `:nome` field, already
18047/// DNS-1123-label-validated at [`Caixa::validate_nome`] (6c992f8) —
18048/// every value reaching this helper is structurally a valid Helm
18049/// chart-name segment. The prepended prefix is a fixed lowercase ASCII
18050/// alphanumeric + hyphen string, so the concatenation is structurally a
18051/// valid Helm chart name by construction (Helm's chart-name accepted
18052/// set is the DNS-1123 label rule, and DNS-1123 labels concatenate with
18053/// the prefix-and-hyphen separator into valid DNS-1123 labels as long
18054/// as the joint length stays ≤ 63 bytes; the M4 admission webhook will
18055/// pin the joint-length invariant when it lands).
18056///
18057/// [cf]: ../../caixa_helm/index.html
18058/// [cm]: ../../caixa_flux/index.html
18059/// [ct]: ../../caixa_tatara/index.html
18060#[must_use]
18061pub fn lareira_chart_name(nome: &str) -> String {
18062    format!("{LAREIRA_CHART_NAME_PREFIX}{nome}")
18063}
18064
18065/// Canonical substrate-fixed Chart.yaml `keywords:` entries every
18066/// rendered `lareira-<nome>` Helm chart carries — the ordered
18067/// (`BTreeSet`-canonical, ascii-alphabetical) list of registry-search
18068/// tags `caixa-helm`'s `build_chart_yaml` unions in on top of the
18069/// caixa author's own `:etiquetas` before folding the joint set into a
18070/// `BTreeSet<String>` for the emitted `Chart.yaml`. Every entry —
18071/// `"caixa-servico"` (the substrate-wide per-`:kind Servico` marker
18072/// axis), `"lareira"` (the [`LAREIRA_CHART_NAME_PREFIX`] chart-family
18073/// tag), `"tatara-lisp"` (the tatara-lisp source-language marker), and
18074/// `"wasm"` (the runtime execution-format marker) — is a load-bearing
18075/// discovery axis for the Artifact Hub keyword-search index and the
18076/// future caixa-registry keyword axis, so a drift between the
18077/// production emit at `caixa-helm::build_chart_yaml` and the two
18078/// substrate-side positive-set sweep tests
18079/// ([`crate::manifest::tests::validate_etiquetas_accepts_canonical_shaped_forms`]
18080/// and this crate's own `chart_keyword_shape_accepts_canonical_forms`)
18081/// would silently cause every rendered chart to miss the search-index
18082/// axis the substrate-fixed tag encodes — a chart published without
18083/// the `"caixa-servico"` tag would silently drop off the
18084/// `helm search hub caixa-servico` results the substrate's chart
18085/// discovery pipeline promises. Two production-side call sites
18086/// (this crate's `is_chart_keyword_shape` docstring narrates the
18087/// four canonical tags verbatim + [`caixa-helm`][ch]'s `build_chart_yaml`
18088/// unions them into the emitted `keywords:` sequence) and two
18089/// test-side positive-sweep sites this array anchors under one source
18090/// of truth.
18091///
18092/// The array is `BTreeSet`-canonical-ordered (ascii-alphabetical: the
18093/// same order the emitted `Chart.yaml` `keywords:` sequence lists them
18094/// after `build_chart_yaml`'s intermediate `BTreeSet<String>` fold), so
18095/// a future substrate-fixed keyword addition (an `"opentelemetry"`
18096/// entry once the caixa-otel collector-pipeline chart lands, a
18097/// `"lunatic"` entry once the wasm-process-runtime marker lands, a
18098/// `"gen_server"` entry once the OTP-shape callback marker lands per
18099/// the [`crate::behavior`] surface) lands at one edit point rather
18100/// than a coordinated four-file sweep across the production emit
18101/// site, the two test-side sweeps, and this docstring. Same
18102/// "one canonical typed array lives in one place" discipline as
18103/// the peer [`crate::aplicacao::WIT_HTTP_SHAPE_PREFIXES`] /
18104/// [`crate::aplicacao::WIT_PUBSUB_SHAPE_PREFIXES`] /
18105/// [`crate::aplicacao::WIT_STORE_SHAPE_PREFIXES`] arm-shape-prefix
18106/// arrays apply on the sibling `:contratos :wit` dispatch-shape axis.
18107///
18108/// Every entry structurally satisfies [`is_chart_keyword_shape`] (the
18109/// substrate's per-`Chart.yaml` `keywords:` entry validation
18110/// predicate) — the substrate-side pin
18111/// `lareira_chart_keywords_each_entry_passes_is_chart_keyword_shape`
18112/// enforces the invariant so a future addition that happens to break
18113/// the shape rule (a leading digit, an uppercase letter, a byte over
18114/// the [`CHART_KEYWORD_MAX_LEN`] cap) fails at caixa-core build time
18115/// rather than surfacing at chart-lint time downstream.
18116///
18117/// [ch]: ../../caixa_helm/index.html
18118pub const LAREIRA_CHART_KEYWORDS: &[&str] = &["caixa-servico", "lareira", "tatara-lisp", "wasm"];
18119
18120/// Canonical OCI URL scheme prefix — the `"oci://"` byte-string every
18121/// substrate-side renderer that composes an OCI artifact reference for a
18122/// Helm chart prepends. The Helm 3 OCI storage protocol (Helm 3.8+) and
18123/// the `FluxCD` `HelmRepository` `type: oci` source both key off this
18124/// literal — `helm pull` / `helm install` / `helm registry login` /
18125/// `FluxCD`'s source-controller all reject any other scheme on the OCI
18126/// path — so a byte-shape drift on this prefix silently splits the
18127/// substrate's published chart references from the cluster-side
18128/// resolvers that consume them at `helm registry` / `FluxCD` reconcile
18129/// time far from the source renderer.
18130///
18131/// The single source of truth every downstream renderer that composes
18132/// an `oci://<registry>/<chart>` reference reaches for —
18133/// [`caixa-tatara`][ct]'s `derive_chart_ref` OCI ref
18134/// (caixa-tatara/src/lib.rs:202), and every future OCI-ref emitter
18135/// (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
18136/// `chart_ref` slot on the tatara `Process` intent, the future
18137/// per-cluster snapshot bundle's OCI chart references, the future
18138/// caixa-otel collector chart's OCI publish shape) inherits the prefix
18139/// through this const by construction. Same "one canonical scheme /
18140/// prefix / separator lives in one place" discipline the peer
18141/// [`LAREIRA_CHART_NAME_PREFIX`] (f7320d7), [`CONTRATO_EDGE_LABEL_SEPARATOR`]
18142/// (6d9b04e), [`PLEME_LABEL_PREFIX`] (b473c00 / 9d9813f) lifts apply
18143/// on the sibling canonical-load-bearing-substrate-string axes.
18144///
18145/// [ct]: ../../caixa_tatara/index.html
18146pub const OCI_SCHEME_PREFIX: &str = "oci://";
18147
18148/// Compose the canonical OCI artifact reference for a per-Servico Helm
18149/// chart — the `oci://<registry>/lareira-<nome>` shape every renderer
18150/// that materializes a chart-publish target (or a cluster-side chart
18151/// resolver keyed off one) composes by prepending
18152/// [`OCI_SCHEME_PREFIX`], joining the caller-supplied registry, and
18153/// appending the per-Servico chart name derived through the canonical
18154/// [`lareira_chart_name`] helper.
18155///
18156/// Single source of truth for the two-axis composition: every consumer
18157/// reaches for this helper rather than re-deriving the
18158/// `format!("oci://{}/lareira-{}", …)` shape inline, so a future change
18159/// to either input axis (the [`OCI_SCHEME_PREFIX`] rebrand once Helm /
18160/// `FluxCD` introduce a new registry protocol, the
18161/// [`LAREIRA_CHART_NAME_PREFIX`] rebrand once `lareira-` outlives its
18162/// scoping intent) is one edit here, not a coordinated sweep across
18163/// every renderer crate's OCI-ref composition site.
18164///
18165/// The rendered reference is the substrate's contract with the
18166/// chart-publishing pipeline (`helm registry login` +
18167/// `helm push chart.tgz oci://<registry>/lareira-<nome>`), the
18168/// cluster-side `FluxCD` `HelmRelease` `chart:` field (which Flux's
18169/// source-controller resolves through the same OCI ref), and the
18170/// tatara `Process` CR's `intent.aplicacao.chart_ref` slot the
18171/// reconciler feeds into `helm install`. Every consumer keys off the
18172/// same byte-shape by construction.
18173///
18174/// [ct]: ../../caixa_tatara/index.html
18175#[must_use]
18176pub fn oci_chart_ref(registry: &str, nome: &str) -> String {
18177    let chart = lareira_chart_name(nome);
18178    format!("{OCI_SCHEME_PREFIX}{registry}/{chart}")
18179}
18180
18181/// The `:nome`-side budget the [`lareira_chart_name`] composition
18182/// imposes on every caixa `:nome` reaching a renderer that derives a
18183/// `lareira-<nome>` artifact (`caixa-helm`'s `ChartDir.name` +
18184/// `Chart.yaml` `name:`, `caixa-flux`'s `cluster_bundle` `HelmRelease`
18185/// `chart:` slot, `caixa-tatara`'s `process_for_aplicacao`
18186/// `release_name` + `oci://<registry>/lareira-<nome>` chart ref).
18187///
18188/// The joint length of `lareira-` + `<nome>` must satisfy the K8s
18189/// DNS-1123 label cap ([`DNS_1123_LABEL_MAX_LEN`] = 63) every downstream
18190/// consumer enforces — Helm's `Chart.yaml::name` field (`helm lint`
18191/// rejects at chart-package time per the DNS-1123 rule), the
18192/// `HelmRelease`'s `release_name` field (the Helm operator's tracking
18193/// secret name is derived from `release_name` and is itself a DNS-1123
18194/// label), the rendered chart's K8s object `metadata.name` axes that
18195/// embed the chart name as a prefix. The arithmetic is therefore
18196/// `DNS_1123_LABEL_MAX_LEN - LAREIRA_CHART_NAME_PREFIX.len()` = 63 - 8
18197/// = 55 bytes the caixa's `:nome` may itself occupy.
18198///
18199/// Lifted to a `pub const` so a future change to either axis
18200/// ([`LAREIRA_CHART_NAME_PREFIX`] rebrand, [`DNS_1123_LABEL_MAX_LEN`]
18201/// shift if Helm/K8s ever relax the chart-name rule) re-derives the
18202/// budget mechanically — every per-axis call site
18203/// ([`is_lareira_chart_name_shape`] consults it, the
18204/// `Caixa::validate_nome_chart_name_budget` diagnostic names it
18205/// verbatim) inherits the new value with no coordinated edit.
18206pub const LAREIRA_CHART_NAME_NOME_MAX_LEN: usize =
18207    DNS_1123_LABEL_MAX_LEN - LAREIRA_CHART_NAME_PREFIX.len();
18208
18209/// Predicate: assert that `nome` produces a [`lareira_chart_name`]
18210/// output satisfying the K8s DNS-1123 label rule — the joint-length
18211/// invariant the canonical `lareira_chart_name` helper's doc comment
18212/// (f7320d7) defers to "the M4 admission webhook will pin … when it
18213/// lands". This predicate lands it at the manifest-validate layer
18214/// rather than waiting for the apiserver.
18215///
18216/// Returns the parser-shaped reason on rejection (without wrapping in
18217/// any error variant) — same call-site discipline as the peer
18218/// [`is_dns_1123_label`] predicate. Each per-axis caller wraps the
18219/// returned reason in its own typed `*Error::*Exceeded { … }` variant
18220/// (today: `Caixa::validate_nome_chart_name_budget` → the new
18221/// [`crate::ManifestError::NomeChartNameBudgetExceeded`] arm).
18222///
18223/// The predicate composes via [`lareira_chart_name`] + [`is_dns_1123_label`]
18224/// — the same two primitives every renderer consults — so a future
18225/// rebrand of either axis (`LAREIRA_CHART_NAME_PREFIX`,
18226/// `DNS_1123_LABEL_MAX_LEN`) re-derives the budget mechanically. A
18227/// `:nome` that already passes [`is_dns_1123_label`] (≤63 bytes,
18228/// boundary-anchored, `[a-z0-9-]` only) but whose prefixed chart name
18229/// exceeds the joint cap is what this gate catches — every byte the
18230/// inner DNS-1123 check accepts the prefixed form may still reject.
18231///
18232/// # Errors
18233///
18234/// Returns a parser-shaped reason naming the budget
18235/// ([`LAREIRA_CHART_NAME_NOME_MAX_LEN`]), the offending `:nome`
18236/// length, and the rendered chart name's length — so the diagnostic is
18237/// self-locating and the author can shorten in one edit.
18238pub fn is_lareira_chart_name_shape(nome: &str) -> Result<(), String> {
18239    let chart_name = lareira_chart_name(nome);
18240    if chart_name.len() > DNS_1123_LABEL_MAX_LEN {
18241        return Err(format!(
18242            "produces `{chart_name}` ({chart_len} bytes), which exceeds the \
18243             DNS-1123 label max length of {DNS_1123_LABEL_MAX_LEN} bytes that \
18244             Helm's `Chart.yaml::name` field and every downstream K8s artifact \
18245             derived from the chart name enforce; the per-`:nome` budget is \
18246             {budget} bytes (DNS-1123 cap minus the `{prefix}` prefix), shorten \
18247             `:nome` to ≤ {budget} bytes",
18248            chart_name = chart_name,
18249            chart_len = chart_name.len(),
18250            budget = LAREIRA_CHART_NAME_NOME_MAX_LEN,
18251            prefix = LAREIRA_CHART_NAME_PREFIX,
18252        ));
18253    }
18254    Ok(())
18255}
18256
18257/// Build the canonical Cilium `matchLabels` selector for a single
18258/// pleme-io program **scoped to its Aplicacao** — the safe default
18259/// every per-Aplicacao mesh renderer (caixa-mesh's
18260/// `cilium_network_policies` `fromEndpoints`, future per-edge policy
18261/// emission, Gateway API `backendRefs` filters) should use, since
18262/// two different Aplicacaos can carry programs with the same `:nome`
18263/// in the same cluster (e.g. two `cart` Servicos under different
18264/// applications) and a `LABEL_PROGRAM`-only selector would match
18265/// pods belonging to the wrong Aplicacao.
18266///
18267/// Returned as a [`BTreeMap`] keyed by `&'static str` so iteration is
18268/// alphabetical (THEORY.md §V.2.7 render determinism: the rendered
18269/// YAML's `matchLabels:` block appears in a deterministic order
18270/// independent of source-code declaration order). The two keys
18271/// alphabetize as [`LABEL_APLICACAO`] before [`LABEL_PROGRAM`], the
18272/// same order the renderer's `serde_yaml::Mapping` iteration will
18273/// preserve through to the rendered YAML.
18274#[must_use]
18275pub fn pleme_program_in_aplicacao_selector(
18276    program: &str,
18277    aplicacao: &str,
18278) -> BTreeMap<&'static str, String> {
18279    let mut out = BTreeMap::new();
18280    out.insert(LABEL_APLICACAO, aplicacao.to_string());
18281    out.insert(LABEL_PROGRAM, program.to_string());
18282    out
18283}
18284
18285/// Build the canonical Cilium `matchLabels` selector for a single
18286/// pleme-io program **without** the Aplicacao constraint —
18287/// deliberately broader than [`pleme_program_in_aplicacao_selector`]
18288/// for the cases where matching a program across every Aplicacao that
18289/// hosts it is the *intent* (cluster-wide rate limits, breakglass
18290/// observability, the per-cluster operator identity scope).
18291///
18292/// **Prefer [`pleme_program_in_aplicacao_selector`]** for typed
18293/// per-Aplicacao mesh emission — using `pleme_program_selector` there
18294/// would let a policy unintentionally match a same-named program in
18295/// a different Aplicacao. Both helpers exist so the caller's *intent*
18296/// (Aplicacao-scoped vs. cluster-wide) is named at the call site,
18297/// not buried in inline label-key string literals.
18298#[must_use]
18299pub fn pleme_program_selector(program: &str) -> BTreeMap<&'static str, String> {
18300    let mut out = BTreeMap::new();
18301    out.insert(LABEL_PROGRAM, program.to_string());
18302    out
18303}
18304
18305/// Convert a typed string-valued mapping (e.g. one of the canonical
18306/// [`pleme_program_selector`] / [`pleme_program_in_aplicacao_selector`]
18307/// selectors, or any caller-built `BTreeMap<&'static str, String>`)
18308/// into a [`serde_yaml::Value::Mapping`] with `String → String` shape —
18309/// the surface every Cilium / Gateway / HTTPRoute / ComputeUnit
18310/// `matchLabels` / `metadata.labels` / `selector` field expects.
18311///
18312/// Iteration order is whatever the input iterator yields; pass a
18313/// [`BTreeMap`] for alphabetical determinism (THEORY.md §V.2.7 render
18314/// determinism: rendered YAML key order is independent of source-code
18315/// declaration order). The two pleme-io selector helpers above already
18316/// return `BTreeMap`s for exactly this reason.
18317///
18318/// Lifted from `caixa-mesh`'s prior `yaml_string_mapping` private
18319/// helper to make the same primitive available to every other
18320/// `caixa-<target>` renderer that needs to emit a string→string YAML
18321/// mapping (the future per-Aplicacao Gateway-API filter rules, the
18322/// caixa-otel resource-attribute emitter, the `app-operator`'s typed
18323/// CR materializer, the per-cluster CiliumClusterwideEnvoyConfig
18324/// renderer for `:politicas` defaults). Without the lift each new
18325/// renderer would re-inline the same five-line `for (k, v)` body and
18326/// inherit the same drift footguns.
18327#[must_use]
18328pub fn yaml_string_mapping<K, V, M>(m: M) -> serde_yaml::Value
18329where
18330    M: IntoIterator<Item = (K, V)>,
18331    K: Into<String>,
18332    V: Into<String>,
18333{
18334    let mut out = serde_yaml::Mapping::new();
18335    for (k, v) in m {
18336        out.insert_str_key(&k.into(), serde_yaml::Value::String(v.into()));
18337    }
18338    serde_yaml::Value::Mapping(out)
18339}
18340
18341/// Wrap a typed string-valued label mapping in the canonical K8s
18342/// [`LabelSelector`][k8s-ls] shape — `{matchLabels: <string-string-map>}`
18343/// — and return it as a [`serde_yaml::Value::Mapping`] ready to drop
18344/// directly under any K8s field that takes a label selector
18345/// (Cilium `endpointSelector` / `fromEndpoints[].matchLabels`, Gateway
18346/// API `BackendRef` filters, ComputeUnit `selector`, Service
18347/// `spec.selector`, the future `mesh.pleme.io/v1alpha1/Aplicacao` CR
18348/// `spec.selector`).
18349///
18350/// Lifted from two inline `serde_yaml::Mapping::new() +
18351/// insert(Value::String("matchLabels".into()), yaml_string_mapping(_))`
18352/// blocks in `caixa-mesh::cilium_network_policies` (the destination
18353/// `endpointSelector` and the source `fromEndpoints[0]` selector) so
18354/// the next renderer to land — the per-`:politicas`
18355/// `CiliumClusterwideEnvoyConfig` emitter (MESH-COMPOSITION §III.2 #3),
18356/// the `app-operator`'s typed `mesh.pleme.io/v1alpha1/Aplicacao` CR
18357/// materializer (§III.2 #5), the M4 cross-cluster fan-out's per-cluster
18358/// `Service`/`HTTPRoute backendRefs` selectors, the future `caixa-otel`
18359/// OpenTelemetry-Collector resource-selector pipeline — gets the
18360/// canonical K8s label-selector shape for free with one function call,
18361/// instead of re-inlining the same four-line `Mapping::new() +
18362/// insert("matchLabels", yaml_string_mapping(_))` boilerplate.
18363///
18364/// V0 emits the equality-based selector axis only (`matchLabels`); the
18365/// set-based axis ([`matchExpressions`][k8s-ls]) is deliberately out
18366/// of scope. A future `:contratos` axis whose selector needs
18367/// `matchExpressions` (e.g. `In`, `NotIn`, `Exists`, `DoesNotExist`
18368/// operators against a label key) is a future struct-shaped extension
18369/// of this helper —
18370/// e.g. a richer [`LabelSelector`] view type with `match_labels` +
18371/// `match_expressions` fields — not a per-renderer rewrite of
18372/// every selector emission site.
18373///
18374/// Iteration order is whatever the input iterator yields; pass a
18375/// [`BTreeMap`] for alphabetical determinism (THEORY.md §V.2.7 render
18376/// determinism: rendered YAML key order is independent of source-code
18377/// declaration order). The two pleme-io selector helpers
18378/// ([`pleme_program_selector`] / [`pleme_program_in_aplicacao_selector`])
18379/// already return `BTreeMap`s for exactly this reason, so a
18380/// `label_selector(pleme_program_in_aplicacao_selector(_, _))` call
18381/// renders deterministically end-to-end.
18382///
18383/// [k8s-ls]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#labelselector-v1-meta
18384#[must_use]
18385pub fn label_selector<K, V, M>(labels: M) -> serde_yaml::Value
18386where
18387    M: IntoIterator<Item = (K, V)>,
18388    K: Into<String>,
18389    V: Into<String>,
18390{
18391    let mut out = serde_yaml::Mapping::new();
18392    out.insert_str_key(KUBE_KEY_MATCH_LABELS, yaml_string_mapping(labels));
18393    serde_yaml::Value::Mapping(out)
18394}
18395
18396/// Build the canonical K8s-resource skeleton — the
18397/// `apiVersion` + `kind` + `metadata.{name, namespace, labels?}`
18398/// block every cluster artifact emitted by every caixa-side renderer
18399/// carries — and return it as a fresh [`serde_yaml::Mapping`] the
18400/// caller adds its `spec:` (and any other top-level keys) to.
18401///
18402/// `labels` is inserted under `metadata.labels` only when non-empty.
18403/// An empty `labels` map leaves the labels key absent — the K8s API
18404/// server's interpretation of "no labels declared" is "labels key
18405/// missing", not `labels: {}` (which serializes differently in some
18406/// YAML libraries and is a sharp tool for label-based selectors that
18407/// match the empty set silently).
18408///
18409/// Iteration order under `metadata` is alphabetical (the inner
18410/// projection is a [`BTreeMap`] keyed by `&'static str`), so the
18411/// rendered YAML's `metadata:` block appears in
18412/// `labels?, name, namespace` order regardless of source-code
18413/// declaration order. Same render-determinism contract the M2 overlay
18414/// helper and the pleme-io selector helpers enshrine.
18415///
18416/// Lifted from three inline `serde_yaml::Mapping::new()` blocks in
18417/// `caixa-mesh` ([`cilium_network_policies`][cnp] CNP construction,
18418/// [`gateway_routes`][gw] Gateway construction, the same fn's
18419/// HTTPRoute construction) so the next renderer to land — the
18420/// per-`:politicas` `CiliumClusterwideEnvoyConfig` emitter, the
18421/// `app-operator`'s typed `mesh.pleme.io/v1alpha1/Aplicacao` CR
18422/// materializer, the M4 cross-cluster fan-out's per-cluster Kustomization
18423/// and HelmRelease emission, the future `caixa-otel`
18424/// OpenTelemetry-Collector pipeline emitter — gets the canonical
18425/// skeleton for free with one function call, instead of re-inlining
18426/// the same five-key insert() boilerplate.
18427///
18428/// [cnp]: https://docs.cilium.io/en/stable/security/policy/index.html
18429/// [gw]: https://gateway-api.sigs.k8s.io/
18430#[must_use]
18431pub fn kube_resource_skeleton(
18432    api_version: &str,
18433    kind: &str,
18434    name: &str,
18435    namespace: &str,
18436    labels: BTreeMap<&'static str, String>,
18437) -> serde_yaml::Mapping {
18438    let mut metadata: BTreeMap<&'static str, serde_yaml::Value> = BTreeMap::new();
18439    metadata.insert(KUBE_KEY_NAME, serde_yaml::Value::String(name.to_string()));
18440    metadata.insert(
18441        KUBE_KEY_NAMESPACE,
18442        serde_yaml::Value::String(namespace.to_string()),
18443    );
18444    if !labels.is_empty() {
18445        metadata.insert(KUBE_KEY_LABELS, yaml_string_mapping(labels));
18446    }
18447
18448    let mut metadata_map = serde_yaml::Mapping::new();
18449    for (k, v) in metadata {
18450        metadata_map.insert_str_key(k, v);
18451    }
18452
18453    let mut out = serde_yaml::Mapping::new();
18454    out.insert_string(KUBE_KEY_API_VERSION, api_version.to_string());
18455    out.insert_string(KUBE_KEY_KIND, kind.to_string());
18456    out.insert_mapping(KUBE_KEY_METADATA, metadata_map);
18457    out
18458}
18459
18460/// Build a single-field [`serde_yaml::Value::Mapping`] from a typed
18461/// `Option<T>` slot — `None` when the slot is unset, `Some(Mapping {
18462/// inner_key: f(t) })` otherwise.
18463///
18464/// The canonical shape every per-`:politicas` overlay across `caixa-mesh`
18465/// uses to wire a typed `MeshPolicy` axis through to its single-key
18466/// cluster artifact:
18467///
18468///   * `:politicas :timeout`        → `timeouts: { request: <duration> }`
18469///     (Gateway API `HTTPRoute.spec.rules[].timeouts`, wired in 5f477a6)
18470///   * `:politicas :retries`        → `retry: { attempts: <number> }`
18471///     (Gateway API `HTTPRoute.spec.rules[].retry`, wired in 23b7f00)
18472///   * `:politicas :mtls-required`  → `authentication: { mode: <enum> }`
18473///     (Cilium `CiliumNetworkPolicy.spec.ingress[].authentication`,
18474///     wired in 878bf81)
18475///
18476/// Until this lift the three call sites each carried a verbatim copy
18477/// of the same six-line block — `let mut m = serde_yaml::Mapping::new();
18478/// m.insert(Value::String(<key>.into()), <value>); Value::Mapping(m)` —
18479/// wrapped in `spec.politicas.<axis>.map(|v| { … })`. Three-of-the-pattern
18480/// across one emit-site (and now structurally one-of-the-pattern in each
18481/// of the next two emit-sites the M3.x roadmap acknowledges: the
18482/// `:circuit-breaker` and `:rate-limit` axes' `CiliumClusterwideEnvoyConfig`
18483/// emitter, MESH-COMPOSITION §III.2 #3) overflows the duplication
18484/// budget; this helper is the lifted typed primitive.
18485///
18486/// The caller passes:
18487///   * the typed `Option<T>` slot,
18488///   * the inner YAML key the artifact's per-axis schema names
18489///     (`request` / `attempts` / `mode` for the three landed overlays;
18490///     `consecutiveErrors` / `requestsPerUnit` for the two roadmap
18491///     axes), and
18492///   * a closure converting the typed `T` into the inner field's
18493///     [`serde_yaml::Value`] (typically a `String` for canonical
18494///     duration / enum scalars or a `Number` for typed integer
18495///     attempt counts).
18496///
18497/// Returns `Some(Mapping)` when the slot is `Some`, `None` otherwise —
18498/// the caller's `if let Some(overlay) = … { rule.insert(<outer_key>,
18499/// overlay.clone()) }` guard for the *outer* key (`timeouts` / `retry`
18500/// / `authentication` — which the per-rule iteration applies to every
18501/// emitted item) becomes the single emission gate, and the *inner*
18502/// shape is built once by the closure.
18503///
18504/// Pairs with the `MeshPolicy::is_empty` predicate at the typed-axis
18505/// emptiness layer: `is_empty()` short-circuits the whole `:politicas`
18506/// block when every axis is `None`; this helper short-circuits the
18507/// per-axis overlay when its single axis is `None`. Two layers, same
18508/// "named-axis-with-None-means-skip-emit" contract THEORY.md §V.2.7
18509/// render determinism extends to.
18510#[must_use]
18511pub fn single_field_overlay<T, F>(
18512    slot: Option<T>,
18513    inner_key: &'static str,
18514    f: F,
18515) -> Option<serde_yaml::Value>
18516where
18517    F: FnOnce(T) -> serde_yaml::Value,
18518{
18519    slot.map(|v| {
18520        let mut m = serde_yaml::Mapping::new();
18521        m.insert_str_key(inner_key, f(v));
18522        serde_yaml::Value::Mapping(m)
18523    })
18524}
18525
18526/// Wrap a single [`serde_yaml::Mapping`] as the sole element of a
18527/// [`serde_yaml::Value::Sequence`], returning the ready-to-drop
18528/// singleton-mapping-sequence `Value`.
18529///
18530/// The canonical shape every K8s-CRD schema-list-shape-required field
18531/// with exactly one entry to emit lands the same
18532/// `Value::Sequence(vec![Value::Mapping(m)])` three-token block in
18533/// front of. Seven identical-shape call sites across
18534/// [`caixa-mesh`][mesh] collapse onto this helper:
18535///
18536///   * Cilium `CiliumNetworkPolicy.spec.ingress[].toPorts[].ports`
18537///     (one `port_entry` per typed edge, wrapped in the CRD's
18538///     required-list-shape `ports:` axis);
18539///   * Cilium `CiliumNetworkPolicy.spec.ingress[].toPorts[].rules.http`
18540///     (one `http_rule` per L7-introspection-capable
18541///     [`crate::WitTarget::Http`] contract, wrapped in the CRD's
18542///     required-list-shape `http:` axis);
18543///   * Cilium `CiliumNetworkPolicy.spec.ingress` (one `ingress_rule`
18544///     per policy — Cilium's CRD schema lists the per-policy ingress
18545///     ruleset even though V0 emits exactly one entry);
18546///   * Gateway API `Gateway.spec.listeners` (one `listener` per
18547///     Gateway — V0 emits the single HTTP-listener shape the sibling
18548///     [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] +
18549///     [`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`] consts pin);
18550///   * Gateway API `HTTPRoute.spec.rules[].matches` (one `match_entry`
18551///     per rule — V0 emits a single per-path prefix-match);
18552///   * Gateway API `HTTPRoute.spec.rules[].backendRefs` (one
18553///     `backend_ref` per rule — V0 emits a single-backend fan-in on
18554///     the `:entrada :para` destination Servico);
18555///   * Gateway API `HTTPRoute.spec.parentRefs` (one `parent_ref` per
18556///     route — every route attaches to exactly one Gateway).
18557///
18558/// Until this lift landed all seven call sites re-inlined the same
18559/// three-token boilerplate — `serde_yaml::` path re-quote,
18560/// `Value::Sequence(_)` promotion, `vec![serde_yaml::Value::Mapping(_)]`
18561/// singleton-list wrapping — around a one-token semantic payload (the
18562/// per-site `Mapping`). Lifting collapses the boilerplate into one
18563/// function call the caller reads as intent (`singleton_mapping_sequence
18564/// (<mapping>)` — "wrap this single mapping as the CRD-required list-
18565/// shape") rather than three hand-spelled positional artifacts. The
18566/// next renderer to land — the per-`:politicas`
18567/// `CiliumClusterwideEnvoyConfig` emitter (MESH-COMPOSITION §III.2 #3,
18568/// which drops singleton `resources:[]` / `listeners:[]` /
18569/// `virtualHosts:[]` blocks under its per-policy CR spec), the
18570/// `app-operator`'s typed `mesh.pleme.io/v1alpha1/Aplicacao` CR
18571/// materializer (§III.2 #5, whose `spec.selectors:[]` / `spec.gates:[]`
18572/// blocks list-shape a single per-Aplicacao entry), the M4 cross-
18573/// cluster fan-out's per-cluster `Service.spec.ports[]` /
18574/// `HTTPRoute.spec.rules[].backendRefs[]` emission, the future
18575/// `caixa-otel` OpenTelemetry-Collector `pipelines.traces.receivers[]`
18576/// / `pipelines.traces.exporters[]` singleton-list-shape emission —
18577/// gets the canonical CRD-list-shape-wrap for free with one function
18578/// call, instead of re-inlining the same three-token block. Peer with
18579/// the sibling render-side helpers on the [`serde_yaml::Value`]-
18580/// construction surface ([`yaml_string_mapping`], [`label_selector`],
18581/// [`kube_resource_skeleton`], [`single_field_overlay`], the sibling
18582/// [`MappingExt::insert_str_key`] primitive) — each closes a distinct
18583/// axis of the K8s-artifact-emit surface's "same shape, written N
18584/// times" duplication.
18585///
18586/// The helper takes an owned [`serde_yaml::Mapping`] (moving into the
18587/// wrapping `vec!` without a clone) because every call site has just
18588/// finished building the mapping locally and passes it by value to the
18589/// insert-under-outer-key step. A [`Value::Mapping`] wrapping of the
18590/// same mapping is one step further along the emit trajectory — the
18591/// helper closes the gap in one primitive.
18592///
18593/// The seven caixa-mesh call sites all followed the same
18594/// insert-under-outer-key step, so the composition
18595/// `mapping.insert_str_key(K, singleton_mapping_sequence(m))` is
18596/// itself lifted onto the sibling [`MappingExt::insert_singleton_mapping_sequence`]
18597/// method — every caixa-mesh site now reaches for the composed
18598/// method rather than nesting the two calls at the call site. This
18599/// standalone helper remains the semantic primitive for the
18600/// singleton-Mapping-list-shape `Value` (the trait method's impl
18601/// composes it internally), and stays public for future callers that
18602/// want the raw `Value::Sequence(vec![Value::Mapping(m)])` payload
18603/// without inserting it under a schema key.
18604///
18605/// [mesh]: https://docs.rs/caixa-mesh
18606#[must_use]
18607#[inline]
18608pub fn singleton_mapping_sequence(m: serde_yaml::Mapping) -> serde_yaml::Value {
18609    serde_yaml::Value::Sequence(vec![serde_yaml::Value::Mapping(m)])
18610}
18611
18612/// Iterator over the string-keyed entries of a [`serde_yaml::Value`]
18613/// that may or may not be a [`serde_yaml::Mapping`] — the canonical
18614/// shape both per-Servico renderers reach for when splicing the
18615/// upstream `ComputeUnit` YAML's `spec.*` fields into their emitted
18616/// output map.
18617///
18618/// Two identical-shape call sites collapse onto this helper — both
18619/// per-Servico renderers previously carried a five-line
18620/// `if let Value::Mapping(_) = spec { for (k, v) in _ { if let
18621/// Some(s) = k.as_str() { <dst>.insert(s, v.clone()) } } }` block:
18622///
18623///   * [`caixa_flux`][flux-programs]'s `programs_yaml_entry` splices
18624///     `computeunit_yaml.spec.*` into the emitted programs.yaml entry
18625///     ([`serde_yaml::Mapping`] destination, via
18626///     [`MappingExt::insert_str_key`]);
18627///   * [`caixa_helm`][helm-values]'s `build_values_yaml` splices the
18628///     same `computeunit_yaml.spec.*` into the values.yaml wrapped
18629///     block ([`std::collections::BTreeMap`]`<String, Value>`
18630///     destination, via `BTreeMap::insert`).
18631///
18632/// Both sites need the same walk (destructure as [`serde_yaml::Mapping`],
18633/// iterate its entries, keep only string-keyed pairs, hand the caller
18634/// each `(&str, &Value)` pair) but drop the values into different
18635/// destination map types, so the lift is at the iterator layer, not
18636/// the insert layer. The caller keeps its own insert idiom (
18637/// [`MappingExt::insert_str_key`] on a [`serde_yaml::Mapping`],
18638/// `BTreeMap::insert` on the [`BTreeMap`]-shaped values block, a
18639/// future renderer's own destination) but reaches through one lifted
18640/// walk with one contract on how non-string-keyed entries are handled:
18641/// silently dropped, matching the behavior both renderers implemented
18642/// inline via the `if let Some(s) = k.as_str()` filter.
18643///
18644/// Returns an empty iterator when `v` is not a
18645/// [`serde_yaml::Value::Mapping`] — the shape the prior `if let
18646/// Value::Mapping(_) = v` arm silently no-ops on (so a Null / String
18647/// / Sequence / Number / Bool `spec` field, itself schema-invalid
18648/// upstream but tolerated by the renderer, contributes zero entries
18649/// to the destination map instead of raising a per-shape error).
18650/// Non-string-keyed entries within a valid Mapping are silently
18651/// dropped — the same behavior the prior `if let Some(s) = k.as_str()`
18652/// arm carried, since `serde_yaml` permits arbitrary [`Value`] keys
18653/// (numeric, boolean, sub-mapping) that don't round-trip through the
18654/// downstream K8s YAML-key surface (which requires string keys).
18655///
18656/// The next per-Servico renderer to land — the future per-Servico
18657/// OCI packager whose emitted `Dockerfile` LABEL block spliced through
18658/// the same `computeunit_yaml.spec.*` string-key set, the M4
18659/// per-Servico `wasm.pleme.io/v1alpha1/ComputeUnit` CR materializer
18660/// whose emitted `spec.*` block splices the same set through onto the
18661/// typed [`kube::api::CustomResource`] view, the future `caixa-otel`
18662/// renderer's per-Servico OpenTelemetry-Collector resource-attribute
18663/// splice — gets the canonical string-key filter for free with one
18664/// method call, instead of re-inlining the same five-line
18665/// `if let Value::Mapping(_) = _` walk.
18666///
18667/// [flux-programs]: https://docs.rs/caixa-flux
18668/// [helm-values]: https://docs.rs/caixa-helm
18669pub fn string_keyed_entries(
18670    v: &serde_yaml::Value,
18671) -> impl Iterator<Item = (&str, &serde_yaml::Value)> + '_ {
18672    v.as_mapping()
18673        .into_iter()
18674        .flat_map(|m| m.iter())
18675        .filter_map(|(k, v)| k.as_str().map(|s| (s, v)))
18676}
18677
18678/// Read the string-scalar value at `metadata.<field>` on a K8s custom
18679/// resource YAML document, returning `None` when either the top-level
18680/// [`KUBE_KEY_METADATA`] block is absent (a defensively-tolerated
18681/// missing sub-mapping — the caller's own test-side `expect(...)` /
18682/// production-side `unwrap_or(...)` names the axis), the requested
18683/// `<field>` scalar is absent under it, or the scalar is present but
18684/// carries a non-string YAML type (a numeric, boolean, or nested
18685/// mapping — invalid K8s CR shape per the apiserver's OpenAPI schema
18686/// but tolerated here as `None` so the readback stays a total
18687/// function). The returned `&str` borrows into the input `Value` — the
18688/// caller decides whether to compare (`==`), clone (`.to_string()`),
18689/// or unwrap-then-panic. The three-hop navigation happens in one
18690/// method call the caller reads as intent
18691/// (`kube_metadata_str_field(<value>, <FIELD>)` — "read this
18692/// `metadata.<FIELD>` string-scalar off this K8s CR document") rather
18693/// than three hand-spelled positional artifacts (the
18694/// `get(KUBE_KEY_METADATA)` outer hop, the `and_then(|m| m.get(<FIELD>))`
18695/// inner hop, the `and_then(|n| n.as_str())` shape gate).
18696///
18697/// The canonical shape 8 call sites across `caixa-mesh` (six tests) +
18698/// `caixa-flux` (one production, one test) previously carried inline
18699/// as the three-line block
18700///
18701/// ```ignore
18702/// value
18703///     .get(KUBE_KEY_METADATA)
18704///     .and_then(|m| m.get(<FIELD>))
18705///     .and_then(|n| n.as_str())
18706/// ```
18707///
18708/// around a one-token semantic payload (the `<FIELD>` axis-key —
18709/// [`KUBE_KEY_NAME`] on the six `metadata.name` per-CNP filter /
18710/// per-CNP name-collect sites in caixa-mesh, [`KUBE_KEY_NAMESPACE`] on
18711/// the caixa-flux `programs_yaml_entry` production readback with
18712/// [`DEFAULT_NAMESPACE`] fallback + the caixa-flux `cluster_bundle`
18713/// test-side `kustomization.yaml` pin).
18714///
18715/// Sites lifted:
18716///
18717///   * caixa-mesh's `cilium_network_policies_emit_per_de_para_edges` —
18718///     the per-CNP names collect ([`KUBE_KEY_NAME`] readback across
18719///     every emitted policy);
18720///   * caixa-mesh's `cilium_fans_same_de_para_edges_into_one_policy` —
18721///     the per-CNP filter on the merged `cart-to-catalog` name
18722///     ([`KUBE_KEY_NAME`] readback + string equality);
18723///   * caixa-mesh's `cilium_pubsub_contracts_skip_l7_rules` — the
18724///     per-CNP find on the `cart-to-catalog` L7-emission witness
18725///     ([`KUBE_KEY_NAME`] readback + string equality);
18726///   * caixa-mesh's `cnp_l4_fallback_port_routes_through_lifted_
18727///     default_servico_port` — the per-CNP find on the
18728///     `payment-to-cart` L4-fallback witness ([`KUBE_KEY_NAME`]
18729///     readback + string equality);
18730///   * caixa-mesh's `cilium_mtls_required_contract_emits_
18731///     authentication_required` — the per-CNP find on the
18732///     `payment-to-cart` mTLS overlay witness ([`KUBE_KEY_NAME`]
18733///     readback + string equality);
18734///   * caixa-mesh's `cilium_mtls_not_required_omits_authentication` —
18735///     the per-CNP find on the `cart-to-payment` overlay-omit
18736///     witness ([`KUBE_KEY_NAME`] readback + string equality);
18737///   * caixa-flux's `programs_yaml_entry` — the production
18738///     `computeunit_yaml.metadata.namespace` readback with
18739///     [`DEFAULT_NAMESPACE`] fallback ([`KUBE_KEY_NAMESPACE`] readback
18740///     + `unwrap_or(DEFAULT_NAMESPACE)`);
18741///   * caixa-flux's `cluster_bundle_kustomization_metadata_namespace_
18742///     pins_flux_system_default` test-side pin — the emitted
18743///     `kustomization.yaml`'s `metadata.namespace` readback
18744///     ([`KUBE_KEY_NAMESPACE`] readback + string equality).
18745///
18746/// Peer to the sibling emit-side [`kube_resource_skeleton`] on the K8s
18747/// CR-document surface: [`kube_resource_skeleton`] closes the per-CR
18748/// `apiVersion` + `kind` + `metadata.{name,namespace,labels}` build
18749/// primitive on the emit side; this closes the reverse per-CR
18750/// `metadata.<field>` readback primitive on the readback side. The
18751/// two together bracket the K8s-CR-YAML round-trip axis so the same
18752/// [`KUBE_KEY_METADATA`] navigation string sits in exactly one place
18753/// on both the write and the read side, and a future
18754/// [`KUBE_KEY_METADATA`] rebrand — a schema-migration to a versioned
18755/// `metadataV2:` axis in a future K8s API-machinery revision, a
18756/// per-CRD-side rename to a wrapped `spec.metadata:` sub-mapping
18757/// under Server-Side-Apply's per-field ownership annotations —
18758/// reaches both sides through the same lifted constant + the same
18759/// lifted helper, not a coordinated rewrite across the emitter +
18760/// every per-CR readback path across every renderer.
18761///
18762/// The next renderer to land — the per-`:politicas`
18763/// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy test
18764/// harness reaches through `metadata.name` to pin per-`(:de, :para)`
18765/// naming and through `metadata.namespace` to pin the
18766/// [`DEFAULT_NAMESPACE`] contract, MESH-COMPOSITION §III.2 #3), the
18767/// `app-operator`'s typed `mesh.pleme.io/v1alpha1/Aplicacao` CR
18768/// materializer's per-CR readback (per-Aplicacao `metadata.name` /
18769/// `metadata.namespace` pins on the emitted `Aplicacao` CR, §III.2 #5),
18770/// the M4 cross-cluster fan-out's per-cluster `HelmRelease.metadata.
18771/// namespace` readback, the future `caixa-otel` per-Servico
18772/// OpenTelemetry-Collector CR's `metadata.name` pin — gets the
18773/// canonical `metadata.<field>` string readback for free with one
18774/// function call, instead of re-inlining the same three-hop chain.
18775///
18776/// The `field` axis stays parametric (rather than pinned to
18777/// [`KUBE_KEY_NAME`] or [`KUBE_KEY_NAMESPACE`] as two separate
18778/// helpers) so the same lift closes every string-scalar sub-field
18779/// under `metadata.*` a future K8s API-machinery revision surfaces
18780/// (`metadata.generateName` on Server-Side-Apply-authored CRs,
18781/// `metadata.resourceVersion` on optimistic-concurrency-controlled
18782/// updates, `metadata.uid` on cross-CR ownerReference bookkeeping) —
18783/// each new axis reaches for the same helper with a new
18784/// [`KUBE_KEY_<AXIS>`] const, not a fresh per-axis helper.
18785pub fn kube_metadata_str_field<'a>(value: &'a serde_yaml::Value, field: &str) -> Option<&'a str> {
18786    value
18787        .get(KUBE_KEY_METADATA)
18788        .and_then(|m| m.get(field))
18789        .and_then(|n| n.as_str())
18790}
18791
18792/// Read the string-scalar value at a top-level `<field>` axis-key on a
18793/// K8s custom resource YAML document — the root-level readback peer to
18794/// [`kube_metadata_str_field`] on the sub-`metadata:` axis. Returns
18795/// `None` when either the requested `<field>` scalar is absent
18796/// (defensively tolerated — the caller's own `unwrap_or(...)` /
18797/// `expect(...)` names the axis) or the scalar is present but carries a
18798/// non-string YAML type (a numeric, boolean, or nested mapping —
18799/// invalid K8s CR shape per the apiserver's OpenAPI schema but
18800/// tolerated here as `None` so the readback stays a total function).
18801/// The returned `&str` borrows into the input `Value` — the caller
18802/// decides whether to compare (`==`), clone (`.to_string()`), or
18803/// unwrap-then-panic. The two-hop navigation happens in one function
18804/// call the caller reads as intent (`kube_root_str_field(<value>,
18805/// <FIELD>)` — "read this K8s CR's top-level `<FIELD>` string-scalar")
18806/// rather than two hand-spelled positional artifacts (the
18807/// `get(<FIELD>)` outer hop, the `and_then(|n| n.as_str())` shape gate).
18808///
18809/// The canonical shape 32 call sites across `caixa-mesh` (24) +
18810/// `caixa-flux` (8) previously carried inline as the two-line block
18811///
18812/// ```ignore
18813/// value
18814///     .get(<FIELD>)
18815///     .and_then(|n| n.as_str())
18816/// ```
18817///
18818/// around a one-token semantic payload (the `<FIELD>` axis-key —
18819/// [`KUBE_KEY_KIND`] on 22 sites, [`KUBE_KEY_API_VERSION`] on 10
18820/// sites). Every routed caller keeps its downstream idiom
18821/// (`.unwrap()`, `.expect(...)`, `== Some(<KIND>)`, `assert_eq!(...,
18822/// Some(<API_VERSION>))`) unchanged — the lift closes the navigation
18823/// surface, not the per-site error-handling posture.
18824///
18825/// Sites lifted include:
18826///
18827///   * caixa-flux's `cluster_bundle_helmrelease_uses_lifted_flux_api_version`
18828///     + peer test-side pins on the emitted `helmrelease.yaml`,
18829///     `gitrepository.yaml`, `kustomization.yaml` per-document
18830///     top-level [`KUBE_KEY_API_VERSION`] axis;
18831///   * caixa-flux's per-document top-level [`KUBE_KEY_KIND`] axis pins
18832///     across the same `cluster_bundle` multi-file sequence;
18833///   * caixa-mesh's `docs.iter().find(|d| d.get(KUBE_KEY_KIND).
18834///     and_then(|k| k.as_str()) == Some(<KIND>))` per-CR filter over
18835///     the emitted `Gateway` + `HTTPRoute` multi-doc sequence — the 15
18836///     `gateway_routes` test-harness `find` sites plus the sibling
18837///     [`CILIUM_KIND_NETWORK_POLICY`] filter in
18838///     `cilium_authentication_mode_serialized_as_yaml_string`;
18839///   * caixa-mesh's per-CR top-level [`KUBE_KEY_API_VERSION`] +
18840///     [`KUBE_KEY_KIND`] discriminator-pair pins across
18841///     `cilium_network_policies_emit_per_de_para_edges` +
18842///     `gateway_routes_emit_gateway_and_httproute_per_aplicacao` +
18843///     sibling gateway/route pins.
18844///
18845/// Peer to sibling [`kube_metadata_str_field`] (6809867) on the K8s
18846/// CR-document readback surface: [`kube_metadata_str_field`] closes
18847/// the `metadata.<field>` string-scalar readback at the sub-`metadata:`
18848/// axis; this closes the root-level `<field>` string-scalar readback at
18849/// the top-level axis. The two together bracket the K8s-CR YAML
18850/// readback surface so every navigation into a rendered K8s CR
18851/// document — the top-level `(apiVersion, kind)` discriminator pair,
18852/// the sub-`metadata.(name, namespace)` identity pair — reaches
18853/// through one canonical lifted helper. A future K8s API-machinery
18854/// rebrand on either axis (a hypothetical `apiVersionV2:` scalar under
18855/// a wrapper CRD group's schema-migration, a Server-Side-Apply-driven
18856/// `metadata.name` rename under per-field ownership annotations)
18857/// reaches every consumer through one lifted helper, not a coordinated
18858/// rewrite across every renderer + every test-side per-CR readback
18859/// path.
18860///
18861/// The `field` axis stays parametric (rather than pinned to
18862/// [`KUBE_KEY_KIND`] or [`KUBE_KEY_API_VERSION`] as two separate
18863/// helpers) so the same lift closes every top-level string-scalar
18864/// axis a future K8s API-machinery revision surfaces (e.g. the
18865/// `caixa-otel` per-Servico OpenTelemetry-Collector CR's top-level
18866/// scalar pins, the future `mesh.pleme.io/v1alpha1/Aplicacao` CR
18867/// materializer's per-CR discriminator readback in the app-operator,
18868/// MESH-COMPOSITION §III.2 #5) — each new axis reaches for the same
18869/// helper with a new [`KUBE_KEY_<AXIS>`] const, not a fresh per-axis
18870/// helper.
18871pub fn kube_root_str_field<'a>(value: &'a serde_yaml::Value, field: &str) -> Option<&'a str> {
18872    value.get(field).and_then(|n| n.as_str())
18873}
18874
18875/// Predicate: does the K8s custom resource YAML document at `value`
18876/// declare its top-level `kind` discriminator axis as exactly `kind`?
18877///
18878/// Composes on top of [`kube_root_str_field`] (ae83f4e) — same two-hop
18879/// `.get(KUBE_KEY_KIND).and_then(as_str)` navigation — and closes the
18880/// "top-level kind-discriminator equality" predicate axis every
18881/// multi-doc mesh emission traversal reaches for to split the emitted
18882/// sequence by CRD-kind.
18883///
18884/// The canonical shape 15 test-side `.find(|d| kube_root_str_field(d,
18885/// KUBE_KEY_KIND) == Some(<KIND>))` + `.filter(|d| … == Some(<KIND>))`
18886/// call sites in `caixa-mesh` previously carried inline as the
18887/// three-token composition
18888///
18889/// ```ignore
18890/// kube_root_str_field(d, KUBE_KEY_KIND) == Some(<KIND>)
18891/// ```
18892///
18893/// around a one-token semantic payload (the `<KIND>` axis-value —
18894/// [`GATEWAY_API_KIND_GATEWAY`] on the per-Gateway filter sites,
18895/// [`GATEWAY_API_KIND_HTTP_ROUTE`] on the per-HTTPRoute filter sites,
18896/// [`CILIUM_KIND_NETWORK_POLICY`] on the sibling CNP filter site). The
18897/// lift collapses the three-token composition — the readback helper
18898/// call, the `== Some(...)` equality wrap, the discriminator-axis pin
18899/// on [`KUBE_KEY_KIND`] — onto one predicate function the caller
18900/// reads as intent (`kube_kind_is(d, <KIND>)` — "is this K8s CR
18901/// document of kind `<KIND>`") rather than as a three-hop
18902/// `readback → wrap → compare` chain.
18903///
18904/// The [`KUBE_KEY_KIND`] axis is pinned inside the helper (unlike the
18905/// parametric `field` axis of the underlying [`kube_root_str_field`])
18906/// because the "does this CR document match kind X" question is a
18907/// semantically-distinct discriminator predicate, not a generic
18908/// scalar-readback: the K8s CRD schema pins `kind` as the load-bearing
18909/// discriminator on every `CustomResource` across every group/version,
18910/// so this predicate lives one abstraction step above the generic
18911/// readback. Peer predicates for other top-level discriminators
18912/// (e.g. `kube_api_version_is` on a hypothetical multi-version
18913/// migration harness) land as sibling helpers with their own
18914/// pinned axis, not as re-parameterizations of this one.
18915///
18916/// Sites lifted:
18917///
18918///   * caixa-mesh's `gateway_routes` test-harness — 14
18919///     `docs.iter().find(|d| kube_root_str_field(d, KUBE_KEY_KIND) ==
18920///     Some(GATEWAY_API_KIND_{GATEWAY,HTTP_ROUTE}))` sites splitting
18921///     the multi-doc emission by `Gateway` vs `HTTPRoute` for per-CR
18922///     body-axis assertions;
18923///   * caixa-mesh's `cilium_authentication_mode_serialized_as_yaml_string`
18924///     — 1 `docs.iter().filter(|d| kube_root_str_field(d,
18925///     KUBE_KEY_KIND) == Some(CILIUM_KIND_NETWORK_POLICY))` filter
18926///     over the emitted CNP sequence.
18927///
18928/// Every future per-CRD-kind traversal (the per-`:politicas`
18929/// `CiliumClusterwideEnvoyConfig` emitter's per-CR filter,
18930/// MESH-COMPOSITION §III.2 #3; the `app-operator`'s
18931/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-status
18932/// discriminator predicate, §III.2 #5; the M4 cross-cluster fan-out's
18933/// per-cluster `HelmRelease` vs `Kustomization` split by kind) reaches
18934/// the same helper by construction, with no `== Some(...)` inline
18935/// composition and no drift surface on the `kind` scalar-key axis.
18936pub fn kube_kind_is(value: &serde_yaml::Value, kind: &str) -> bool {
18937    kube_root_str_field(value, KUBE_KEY_KIND) == Some(kind)
18938}
18939
18940/// Locate the first K8s CR YAML document in `docs` whose top-level
18941/// `kind` discriminator axis equals `kind`.
18942///
18943/// Composes on top of [`kube_kind_is`] (2902d9d) — same one-hop
18944/// `.get(KUBE_KEY_KIND).and_then(as_str) == Some(kind)` predicate —
18945/// and closes the "find the one document of a given kind inside a
18946/// multi-doc mesh emission" navigator axis every per-Aplicacao
18947/// renderer's post-emit test harness reaches for to split the
18948/// emitted sequence by CRD-kind before probing a per-CR body-axis.
18949///
18950/// The canonical shape 14 test-side
18951///
18952/// ```ignore
18953/// docs.iter().find(|d| kube_kind_is(d, <KIND>))
18954/// ```
18955///
18956/// call sites in [`caixa-mesh`][mesh]'s `gateway_routes` +
18957/// `cilium_network_policies` test harnesses previously threaded the
18958/// three-token `.iter().find(closure)` combinator chain around a
18959/// one-token semantic payload (the `<KIND>` axis-value —
18960/// [`GATEWAY_API_KIND_GATEWAY`] on the per-Gateway navigator sites,
18961/// [`GATEWAY_API_KIND_HTTP_ROUTE`] on the per-HTTPRoute navigator
18962/// sites). The lift collapses the three-token chain — the `.iter()`
18963/// receiver-widen, the `.find(closure)` combinator, the inline
18964/// closure wrap around [`kube_kind_is`] — onto one navigator
18965/// function the caller reads as intent (`find_by_kind(&docs,
18966/// <KIND>)` — "give me the K8s CR document of kind `<KIND>`")
18967/// rather than as a receiver-widen → combinator → predicate chain.
18968///
18969/// Composition-symmetric to [`kube_kind_is`]: the lifted predicate
18970/// answers "does *this* one document match kind `<KIND>`?", the
18971/// lifted navigator answers "find the one document of kind
18972/// `<KIND>` in *this list*?". Same axis, different arity — the two
18973/// call shapes emit-side test harnesses reach for when splitting
18974/// multi-doc CR emissions by top-level kind.
18975///
18976/// Every future per-CRD-kind multi-doc-navigator site (the
18977/// per-`:politicas` `CiliumClusterwideEnvoyConfig` emitter's post-
18978/// emit test harness, MESH-COMPOSITION §III.2 #3; the
18979/// `app-operator`'s `mesh.pleme.io/v1alpha1/Aplicacao` CR
18980/// materializer's per-status doc-navigator, §III.2 #5; the M4
18981/// cross-cluster fan-out's per-cluster multi-doc split by kind)
18982/// reaches the same helper by construction, with no inline
18983/// `.iter().find(closure)` combinator chain and no drift surface
18984/// on the receiver-widen or combinator axes.
18985///
18986/// [mesh]: https://github.com/pleme-io/caixa/tree/main/caixa-mesh
18987#[must_use]
18988pub fn find_by_kind<'a>(
18989    docs: &'a [serde_yaml::Value],
18990    kind: &str,
18991) -> Option<&'a serde_yaml::Value> {
18992    docs.iter().find(|d| kube_kind_is(d, kind))
18993}
18994
18995/// Upsert `new_entry` into a typed sequence of programs.yaml-shaped
18996/// entries by matching on `new_entry`'s `<name_key>` scalar — the
18997/// idempotent "replace-in-place if present, else append" contract
18998/// every writer-side aggregator overlay lands the same 11-line block
18999/// in front of. Returns `Ok(true)` when the entry was appended new,
19000/// `Ok(false)` when an existing entry with the same `<name_key>`
19001/// value was replaced in place (preserving position); returns
19002/// `on_missing_name()` when `new_entry` doesn't carry `<name_key>`
19003/// as a string scalar (the caller's own typed
19004/// [`crate::RenderError`]-shaped error surface, threaded through the
19005/// closure so this helper stays crate-agnostic).
19006///
19007/// Two identical-shape call sites collapse onto this helper — the
19008/// two [`caixa-flux`] writer-side upsert paths that both land a
19009/// programs.yaml entry into a `programs:` sequence differing only
19010/// on the outer navigation:
19011///
19012///   * [`caixa_flux::upsert_into_helmrelease_programs`][helm-up] —
19013///     the aggregator-HelmRelease shape, upserting into
19014///     `spec.values.programs[]` on a `HelmRelease` document;
19015///   * [`caixa_flux::upsert_into_programs_yaml`][yaml-up] — the
19016///     bare-values.yaml shape, upserting into `programs[]` at the
19017///     values.yaml root.
19018///
19019/// Until this lift landed both call sites re-inlined the same
19020/// verbatim 11-line block — extract-name-scalar-or-error, iterate
19021/// the sequence, replace-in-place-on-match else fall through to
19022/// push — with no compile-time link between the two: a rebrand on
19023/// either side (a per-entry match key rename beyond the currently-
19024/// lifted [`crate::FLEET_PROGRAMS_KEY_NAME`], the idempotency
19025/// contract's semantic reshaping — e.g. matching on
19026/// `(name, namespace)` for the M4 multi-namespace aggregator flow
19027/// once the `lareira-fleet-programs` chart admits per-entry
19028/// `namespace:` overrides, the return-value's `bool`-shape shift
19029/// once "replace" grows a merge-semantics axis) would silently
19030/// desynchronize the two writer-side paths — one path idempotently
19031/// upserts under the new contract while the other silently keeps
19032/// the old shape, and the failure surfaces at aggregator-apply
19033/// time as a duplicated / missing / mis-merged entry far from the
19034/// rebrand commit's source. Peer of the sibling render-side lifts
19035/// ([`single_field_overlay`], [`servico_m2_overlay`],
19036/// [`insert_first_seen`]) on the same "the same shape written
19037/// verbatim ≥ 2 times becomes a typed helper" trajectory THEORY.md
19038/// §I.3.5 promotes to a build-time concern.
19039///
19040/// The `name_key` axis stays parametric (rather than pinned to
19041/// [`crate::FLEET_PROGRAMS_KEY_NAME`] inside the helper) so a
19042/// future per-entry match on a different discriminator scalar (an
19043/// M4 `id:` axis promoted alongside `name:`, the future
19044/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-entry
19045/// `spec.selector` upsert path) reaches for the same helper with a
19046/// different key rather than re-inlining the loop. The closure-
19047/// shaped error surface (rather than a bare `Result<bool,
19048/// &'static str>` or an added typed error variant in this crate)
19049/// keeps every caller's own error enum authoritative — the
19050/// diagnostic remediation for a missing-name-scalar in a programs-
19051/// yaml entry rightly names the caller's aggregator schema
19052/// (`spec.values.programs[].name` for the `HelmRelease` shape,
19053/// `programs[].name` for the bare values.yaml shape), not this
19054/// generic helper.
19055///
19056/// [helm-up]: ../../caixa_flux/fn.upsert_into_helmrelease_programs.html
19057/// [yaml-up]: ../../caixa_flux/fn.upsert_into_programs_yaml.html
19058///
19059/// # Errors
19060///
19061/// Returns `on_missing_name()` when `new_entry.get(name_key)` is
19062/// not a [`serde_yaml::Value::String`] — the closure surfaces the
19063/// caller's own typed error variant naming the offending schema
19064/// axis. On success returns `Ok(true)` for a newly-appended entry,
19065/// `Ok(false)` for an in-place replacement.
19066pub fn upsert_named_entry<E>(
19067    arr: &mut Vec<serde_yaml::Value>,
19068    new_entry: serde_yaml::Value,
19069    name_key: &'static str,
19070    on_missing_name: impl FnOnce() -> E,
19071) -> Result<bool, E> {
19072    let new_name = match new_entry.get(name_key).and_then(|n| n.as_str()) {
19073        Some(s) => s.to_string(),
19074        None => return Err(on_missing_name()),
19075    };
19076    for slot in arr.iter_mut() {
19077        if slot.get(name_key).and_then(|n| n.as_str()) == Some(&new_name) {
19078            *slot = new_entry;
19079            return Ok(false);
19080        }
19081    }
19082    arr.push(new_entry);
19083    Ok(true)
19084}
19085
19086/// Render the M2 typed-slot YAML overlay for a Caixa: the camelCase
19087/// `(key, value)` fragments every per-Servico renderer
19088/// ([`caixa-helm`]'s values block, [`caixa-flux`]'s programs.yaml
19089/// entry) merges into its target with `or_insert` semantics so explicit
19090/// `spec.*` fields from the ComputeUnit YAML take precedence over the
19091/// manifest-derived overlay.
19092///
19093/// Keys (alphabetically ordered, since the return type is
19094/// [`BTreeMap`]) match the ComputeUnit / pleme-computeunit values
19095/// schema:
19096///
19097///   * [`M2_KEY_BEHAVIOR`] — present iff `caixa.behavior` is `Some`
19098///     and `BehaviorSpec::is_empty` returns `false`.
19099///   * [`M2_KEY_LIMITS`] — present iff `caixa.limits` is `Some` and
19100///     `LimitsSpec::is_empty` returns `false`.
19101///   * [`M2_KEY_UPGRADE_FROM`] — present iff `caixa.upgrade_from` is
19102///     non-empty.
19103///
19104/// An entirely empty M2 surface returns an empty map; the renderer
19105/// merges zero fragments and emits no extra keys (the per-renderer
19106/// "empty M2 slots do not appear" tests pin this invariant —
19107/// `caixa_helm::tests::empty_m2_slots_do_not_appear` and
19108/// `caixa_flux::tests::empty_m2_slots_do_not_appear_in_programs_yaml_entry`).
19109///
19110/// # Errors
19111///
19112/// Returns [`RenderError::Yaml`] if `serde_yaml::to_value` fails for
19113/// any of the typed M2 slot values. The prior inline block silently
19114/// substituted [`serde_yaml::Value::Null`] in this case, which renders
19115/// as e.g. `limits: null` — indistinguishable from "the author omitted
19116/// the slot" once it leaves the typed surface.
19117pub fn servico_m2_overlay(
19118    caixa: &Caixa,
19119) -> Result<BTreeMap<&'static str, serde_yaml::Value>, RenderError> {
19120    let mut out = BTreeMap::new();
19121    if let Some(limits) = caixa.limits() {
19122        if !limits.is_empty() {
19123            let v = serde_yaml::to_value(limits).map_err(|source| RenderError::Yaml {
19124                slot: M2_KEY_LIMITS,
19125                source,
19126            })?;
19127            out.insert(M2_KEY_LIMITS, v);
19128        }
19129    }
19130    if let Some(behavior) = caixa.behavior() {
19131        if !behavior.is_empty() {
19132            let v = serde_yaml::to_value(behavior).map_err(|source| RenderError::Yaml {
19133                slot: M2_KEY_BEHAVIOR,
19134                source,
19135            })?;
19136            out.insert(M2_KEY_BEHAVIOR, v);
19137        }
19138    }
19139    if !caixa.upgrade_from().is_empty() {
19140        let v = serde_yaml::to_value(caixa.upgrade_from()).map_err(|source| RenderError::Yaml {
19141            slot: M2_KEY_UPGRADE_FROM,
19142            source,
19143        })?;
19144        out.insert(M2_KEY_UPGRADE_FROM, v);
19145    }
19146    Ok(out)
19147}
19148
19149/// Compose the canonical per-Servico value-block splice every per-Servico
19150/// renderer applies to the target values / entry mapping — the two-step
19151/// sequence [`caixa_helm::build_values_yaml`] and
19152/// [`caixa_flux::programs_yaml_entry`] both re-derived inline before this
19153/// lift:
19154///
19155///   1. Splice every string-keyed entry from the `ComputeUnit` YAML's
19156///      `spec.*` sub-mapping (routed through [`string_keyed_entries`],
19157///      preserving the source Mapping's insertion order).
19158///   2. Overlay the M2 typed slots (routed through
19159///      [`servico_m2_overlay`], `BTreeMap` key-ordered) at every M2 key
19160///      not already claimed by step 1 — the `or_insert` precedence rule
19161///      the two prior inline call sites shared, promoted here to a
19162///      filtered append so the returned `Vec` is drop-in for a target
19163///      mapping whose insertion order is load-bearing (caixa-flux's
19164///      `serde_yaml::Mapping` preserves it; caixa-helm's `BTreeMap`
19165///      re-sorts by key, so both consumer shapes stay byte-identical
19166///      to their prior inline blocks under this lift).
19167///
19168/// Returns a `Vec<(String, serde_yaml::Value)>` in insertion order —
19169/// spec.* entries first (original ordering preserved), then the M2 slots
19170/// that weren't claimed by spec.* (in [`servico_m2_overlay`]'s canonical
19171/// BTreeMap-key ordering: `behavior` → `limits` → `upgradeFrom`).
19172/// Callers extend their target mapping by iterating the `Vec` and
19173/// inserting each pair with their own map type's canonical insert.
19174///
19175/// Until this lift landed the two prior inline blocks each carried the
19176/// same three-shape composition: `for (k, v) in
19177/// caixa_core::string_keyed_entries(spec) { <insert>(k, v.clone()); }`
19178/// followed by `for (key, value) in caixa_core::servico_m2_overlay(caixa)?
19179/// { <entry-and-or-insert>(key, value); }`. A future change to the
19180/// per-Servico splice / overlay composition — the M4 typed per-edge
19181/// policy overlay slot addition (MESH-COMPOSITION §III.2 #3), a change
19182/// to the spec.* / M2 precedence rule (e.g. reversing to "M2 wins on
19183/// collision" once per-Aplicacao operator overrides land), a
19184/// canonicalization pass on the merged key set (e.g. rejecting empty
19185/// string keys, casing-normalization on DNS-1123 labels) — would have
19186/// to be threaded through both renderers in lockstep or one would
19187/// silently diverge from the other on which keys it emitted and in
19188/// what order. Peer with the lifted [`servico_m2_overlay`] on the
19189/// per-Servico M2-overlay axis (10bf310 / 0e84fb9 on the sibling
19190/// upsert-loop / test-side probe axes) — completes the
19191/// "one canonical splice / overlay composition per typed axis"
19192/// discipline the M2 overlay lift established, now on the composed
19193/// spec.*+M2 axis every per-Servico renderer entry-point navigates.
19194///
19195/// # Errors
19196///
19197/// Propagates [`RenderError::Yaml`] from [`servico_m2_overlay`] when
19198/// `serde_yaml::to_value` fails for any typed M2 slot value — the same
19199/// error surface [`servico_m2_overlay`]'s docstring names.
19200pub fn servico_spec_and_m2_overlay_entries(
19201    caixa: &Caixa,
19202    spec: &serde_yaml::Value,
19203) -> Result<Vec<(String, serde_yaml::Value)>, RenderError> {
19204    let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();
19205    let mut out: Vec<(String, serde_yaml::Value)> = Vec::new();
19206    for (k, v) in string_keyed_entries(spec) {
19207        seen.insert(k.to_string());
19208        out.push((k.to_string(), v.clone()));
19209    }
19210    for (key, value) in servico_m2_overlay(caixa)? {
19211        if !seen.contains(key) {
19212            out.push((key.to_string(), value));
19213        }
19214    }
19215    Ok(out)
19216}
19217
19218/// Bracket a typed `u32` axis with the "zero-floor + upper-cap" gate
19219/// pair every capped-`u32` `:politicas` / `:supervisor` / `:limits`
19220/// axis carries. Returns `on_zero()` when `value == 0`,
19221/// `on_cap_exceeded(value)` when `value > cap`, `Ok(())` otherwise.
19222///
19223/// The zero-floor arm strictly precedes the cap arm so a literal `0`
19224/// value surfaces the self-locating zero diagnostic (which every
19225/// per-axis error variant already documents an "omit the axis to
19226/// express no-bound" remediation for) rather than the misleading
19227/// `0 > cap` false-negative on the cap arm. Same ordering discipline
19228/// every existing per-axis inline `if value == 0 { … } if value > CAP
19229/// { … }` block already applies — this lift makes the ordering a
19230/// property of the helper, not a per-call-site convention six sites
19231/// re-derive.
19232///
19233/// Six identical-shape call sites collapse onto this helper:
19234///
19235///   * [`crate::AplicacaoSpec::validate_politicas`] on
19236///     `MeshPolicy::retries` (zero →
19237///     [`crate::AplicacaoError::PolicyRetriesZero`], cap →
19238///     [`crate::AplicacaoError::PolicyRetriesExceedsCap`],
19239///     cap = [`crate::POLICY_RETRIES_MAX`]),
19240///     `CircuitBreaker::max_failures` (zero →
19241///     [`crate::AplicacaoError::PolicyBreakerZeroFailures`], cap →
19242///     [`crate::AplicacaoError::PolicyBreakerMaxFailuresExceedsCap`],
19243///     cap = [`crate::POLICY_BREAKER_MAX_FAILURES_MAX`]), and
19244///     `RateLimit::rate` (zero →
19245///     [`crate::AplicacaoError::PolicyRateLimitZero`], cap →
19246///     [`crate::AplicacaoError::PolicyRateLimitExceedsCap`],
19247///     cap = [`crate::POLICY_RATE_LIMIT_MAX`]);
19248///   * [`crate::SupervisorSpec::validate`] on `max_restarts`
19249///     (zero → [`crate::SupervisorError::ZeroMaxRestarts`], cap →
19250///     [`crate::SupervisorError::MaxRestartsExceedsCap`],
19251///     cap = [`crate::SUPERVISOR_MAX_RESTARTS_MAX`]);
19252///   * [`crate::LimitsSpec::validate`] on `cpu`
19253///     (zero → [`crate::LimitsError::CpuZero`], cap →
19254///     [`crate::LimitsError::CpuExceedsCap`],
19255///     cap = [`crate::LIMITS_CPU_MILLICORES_MAX`]).
19256///
19257/// Peer to [`require_positive_bounded_u64`] on the `u64`-typed axes
19258/// ([`crate::LimitsSpec::fuel`]). Generic over the caller's error enum
19259/// so the same helper reaches every crate-level [`thiserror`] surface
19260/// — the six per-axis error variants remain the source of truth for
19261/// each axis's remediation prose; the helper only sequences the two
19262/// gate arms in canonical order and threads the value into the cap
19263/// arm's discriminator field.
19264///
19265/// # Errors
19266///
19267/// Returns `on_zero()` for `value == 0`; returns `on_cap_exceeded(value)`
19268/// for `value > cap`; returns `Ok(())` otherwise.
19269pub fn require_positive_bounded_u32<E>(
19270    value: u32,
19271    cap: u32,
19272    on_zero: impl FnOnce() -> E,
19273    on_cap_exceeded: impl FnOnce(u32) -> E,
19274) -> Result<(), E> {
19275    if value == 0 {
19276        return Err(on_zero());
19277    }
19278    if value > cap {
19279        return Err(on_cap_exceeded(value));
19280    }
19281    Ok(())
19282}
19283
19284/// Peer of [`require_positive_bounded_u32`] on the `u64`-typed axes.
19285/// Returns `on_zero()` when `value == 0`, `on_cap_exceeded(value)`
19286/// when `value > cap`, `Ok(())` otherwise. See
19287/// [`require_positive_bounded_u32`] for the ordering / lift rationale
19288/// (same "zero-floor arm strictly precedes cap arm so `0` surfaces
19289/// the self-locating diagnostic" discipline the peer helper documents).
19290///
19291/// The single existing call site is [`crate::LimitsSpec::validate`] on
19292/// `fuel` (zero → [`crate::LimitsError::FuelZero`], cap →
19293/// [`crate::LimitsError::FuelExceedsCap`], cap =
19294/// [`crate::LIMITS_FUEL_MAX`]). Lifted alongside its `u32` peer so
19295/// the two integer-typed axes on this discipline share one canonical
19296/// entry-point — a future `u64`-typed axis (a hypothetical
19297/// per-Aplicacao byte-budget cap, the M4 per-edge policy resolver's
19298/// byte-throughput axis) reaches for the same helper by construction.
19299///
19300/// # Errors
19301///
19302/// Returns `on_zero()` for `value == 0`; returns `on_cap_exceeded(value)`
19303/// for `value > cap`; returns `Ok(())` otherwise.
19304pub fn require_positive_bounded_u64<E>(
19305    value: u64,
19306    cap: u64,
19307    on_zero: impl FnOnce() -> E,
19308    on_cap_exceeded: impl FnOnce(u64) -> E,
19309) -> Result<(), E> {
19310    if value == 0 {
19311        return Err(on_zero());
19312    }
19313    if value > cap {
19314        return Err(on_cap_exceeded(value));
19315    }
19316    Ok(())
19317}
19318
19319/// Bracket a typed `Duration` axis with the "zero-floor +
19320/// canonical-form + upper-cap" three-arm gate every typed-`Duration`
19321/// slot in the crate carries. Returns `on_zero()` when `value` is
19322/// `Duration::ZERO`, `on_not_canonical(value)` when `value` carries
19323/// sub-millisecond residue the shared
19324/// [`crate::supervisor::duration_codec`] cannot round-trip losslessly,
19325/// `on_cap_exceeded(value)` when `value > cap`, `Ok(())` otherwise.
19326///
19327/// The three arms fire in canonical `zero → not-canonical → cap` order,
19328/// matching the discipline every existing per-axis inline block already
19329/// applied by hand: the zero-floor arm precedes the canonical-form arm
19330/// so `Duration::ZERO` (whose `subsec_nanos() == 0` makes it accepted
19331/// by the canonical-form predicate) surfaces the self-locating zero
19332/// diagnostic — every per-axis zero variant already documents an
19333/// "omit the axis to express no-bound" remediation — rather than the
19334/// misleading no-op the canonical arm would return; the canonical-form
19335/// arm then precedes the cap arm so a `Duration` that is *both*
19336/// sub-millisecond and above-cap surfaces the more fundamental
19337/// round-trip-shape diagnostic first (the cap's `1ms..=<cap>`
19338/// remediation would be misleading when no integer-ms form of the
19339/// offending value exists). Same ordering discipline the peer
19340/// [`require_positive_bounded_u32`] applies on its two arms — this
19341/// lift makes the three-arm ordering a property of the helper, not a
19342/// per-call-site convention four sites re-derived by hand.
19343///
19344/// Four identical-shape call sites collapse onto this helper — one for
19345/// each typed-`Duration` slot in the crate:
19346///
19347///   * [`crate::AplicacaoSpec::validate`] on
19348///     [`crate::MeshPolicy::timeout`] (zero →
19349///     [`crate::AplicacaoError::PolicyTimeoutZero`], not-canonical →
19350///     [`crate::AplicacaoError::PolicyTimeoutNotCanonical`], cap →
19351///     [`crate::AplicacaoError::PolicyTimeoutExceedsCap`],
19352///     cap = [`crate::POLICY_TIMEOUT_MAX`]) and
19353///     [`crate::CircuitBreaker::window`] (zero →
19354///     [`crate::AplicacaoError::PolicyBreakerZeroWindow`],
19355///     not-canonical →
19356///     [`crate::AplicacaoError::PolicyBreakerWindowNotCanonical`],
19357///     cap → [`crate::AplicacaoError::PolicyBreakerWindowExceedsCap`],
19358///     cap = [`crate::POLICY_BREAKER_WINDOW_MAX`]);
19359///   * [`crate::LimitsSpec::validate`] on
19360///     [`crate::LimitsSpec::wall_clock`] (zero →
19361///     [`crate::LimitsError::WallClockZero`], not-canonical →
19362///     [`crate::LimitsError::WallClockNotCanonical`], cap →
19363///     [`crate::LimitsError::WallClockExceedsCap`],
19364///     cap = [`crate::LIMITS_WALL_CLOCK_MAX`]);
19365///   * [`crate::SupervisorSpec::validate`] on
19366///     [`crate::SupervisorSpec::restart_window`] (zero →
19367///     [`crate::SupervisorError::RestartWindowZero`], not-canonical →
19368///     [`crate::SupervisorError::RestartWindowNotCanonical`], cap →
19369///     [`crate::SupervisorError::RestartWindowExceedsCap`],
19370///     cap = [`crate::SUPERVISOR_RESTART_WINDOW_MAX`]).
19371///
19372/// Peer to [`require_positive_bounded_u32`] /
19373/// [`require_positive_bounded_u64`] on the integer-typed capped axes;
19374/// the four typed-`Duration` axes and the four typed-integer axes now
19375/// route through one helper each, so a future axis reaching for the
19376/// same discipline lands in exactly one place. Generic over the
19377/// caller's error enum so the same helper reaches every crate-level
19378/// [`thiserror`] surface — the ten per-axis error variants remain the
19379/// source of truth for each axis's remediation prose; the helper only
19380/// sequences the three gate arms in canonical order and threads the
19381/// value into the not-canonical / cap arms' discriminator fields.
19382///
19383/// # Errors
19384///
19385/// Returns `on_zero()` for `value.is_zero()`; returns
19386/// `on_not_canonical(value)` when `value` carries sub-millisecond
19387/// residue (`value.subsec_nanos() % 1_000_000 != 0`); returns
19388/// `on_cap_exceeded(value)` for `value > cap`; returns `Ok(())`
19389/// otherwise.
19390pub fn require_positive_canonical_bounded_duration<E>(
19391    value: std::time::Duration,
19392    cap: std::time::Duration,
19393    on_zero: impl FnOnce() -> E,
19394    on_not_canonical: impl FnOnce(std::time::Duration) -> E,
19395    on_cap_exceeded: impl FnOnce(std::time::Duration) -> E,
19396) -> Result<(), E> {
19397    if value.is_zero() {
19398        return Err(on_zero());
19399    }
19400    if !crate::supervisor::duration_codec::is_integer_millisecond_duration(value) {
19401        return Err(on_not_canonical(value));
19402    }
19403    if value > cap {
19404        return Err(on_cap_exceeded(value));
19405    }
19406    Ok(())
19407}
19408
19409/// Bracket a `:versao` requirement-string axis with the shared
19410/// "empty-first, then [`crate::parse_requirement`]" gate pair every
19411/// dep-shaped `:versao` slot carries. Returns `on_empty()` when
19412/// `versao.is_empty()`, `on_invalid(reason)` when
19413/// [`crate::parse_requirement`] rejects the non-empty input, `Ok(())`
19414/// otherwise.
19415///
19416/// The empty-first arm strictly precedes the parse arm so a literal
19417/// `""` value surfaces the self-locating empty diagnostic every
19418/// per-axis error variant already documents an "omit the axis to
19419/// express any-version" remediation for, rather than the misleading
19420/// parse-side no-op — [`crate::parse_requirement("")`][crate::parse_requirement]
19421/// hits `semver::VersionReq::parse("")` which returns
19422/// `Ok(VersionReq { comparators: [] })` (semantically identical to
19423/// [`semver::VersionReq::STAR`]), so without the empty-first arm an
19424/// authored blank `:versao "" ` would silently round-trip as an
19425/// implicit `"*"` — the same "silent widening" footgun the peer
19426/// [`require_positive_bounded_u32`] closes on its zero-floor arm.
19427///
19428/// The three existing call sites — [`crate::dep::Dep::validate`] on
19429/// [`crate::dep::Dep::versao`] (empty → [`crate::DepError::VersaoEmpty`],
19430/// invalid → [`crate::DepError::VersaoInvalid`]),
19431/// [`crate::AplicacaoSpec::validate_membros`] on
19432/// [`crate::aplicacao::Membro::versao`] (empty →
19433/// [`crate::AplicacaoError::MembroVersaoEmpty`], invalid →
19434/// [`crate::AplicacaoError::MembroVersaoInvalid`]), and
19435/// [`crate::SupervisorSpec::validate`] on
19436/// [`crate::supervisor::ChildSpec::versao`] (empty →
19437/// [`crate::SupervisorError::EmptyChildVersion`], invalid →
19438/// [`crate::SupervisorError::ChildVersaoInvalid`]) — each formerly
19439/// inlined this two-arm cascade verbatim. Lifting to one canonical
19440/// entry-point closes the drift footgun structurally: a future
19441/// widening of the accepted requirement-shape (a hypothetical
19442/// git-tag-prefix leniency, a per-axis strictness override, or the
19443/// M4 typed-resolver's `constraint:` axis on
19444/// [`ABSORPTION-ROADMAP.md`]'s per-resolver-step trajectory) reaches
19445/// every dep-shaped `:versao` consumer by one edit at this helper,
19446/// not a coordinated rewrite across three modules.
19447///
19448/// Peer of [`require_positive_bounded_u32`] /
19449/// [`require_positive_bounded_u64`] on the same closure-based
19450/// caller-error-variant discipline — the caller owns the enum
19451/// variant + its self-locating discriminator fields
19452/// (`nome`/`caixa`, `versao`), this helper only sequences the two
19453/// gate arms in canonical order and threads the parser's
19454/// `semver`-shaped reason into the invalid arm's `reason:` field.
19455///
19456/// # Errors
19457///
19458/// Returns `on_empty()` for `versao.is_empty()`; returns
19459/// `on_invalid(reason)` when [`crate::parse_requirement`] rejects
19460/// the non-empty input (the parser's `to_string()` output threaded
19461/// through as the invalid arm's `reason:`); returns `Ok(())`
19462/// otherwise.
19463pub fn require_valid_versao_requirement<E>(
19464    versao: &str,
19465    on_empty: impl FnOnce() -> E,
19466    on_invalid: impl FnOnce(String) -> E,
19467) -> Result<(), E> {
19468    if versao.is_empty() {
19469        return Err(on_empty());
19470    }
19471    if let Err(e) = crate::parse_requirement(versao) {
19472        return Err(on_invalid(e.to_string()));
19473    }
19474    Ok(())
19475}
19476
19477/// Bracket a K8s DNS-1123-label-shaped axis with the shared
19478/// "empty-first, then [`is_dns_1123_label`]" gate pair every Servico-
19479/// name reference slot carries. Returns `on_empty()` when
19480/// `value.is_empty()`, `on_invalid(reason)` when [`is_dns_1123_label`]
19481/// rejects the non-empty input, `Ok(())` otherwise.
19482///
19483/// The empty-first arm strictly precedes the shape arm so a literal
19484/// `""` value surfaces each per-axis error variant's narrower self-
19485/// locating `_Empty` diagnostic (`MembroCaixaEmpty`, `PlacementClusterEmpty`,
19486/// `EntradaParaEmpty`, `NomeEmpty`, `EmptyChildName`, `ModuleEmpty`, …)
19487/// rather than the shared predicate's generic "must not be empty" prose
19488/// — the same "misframed generic diagnostic" footgun the peer
19489/// [`require_valid_versao_requirement`] closes on its empty arm. The
19490/// invalid arm threads the predicate's parser-shaped reason verbatim
19491/// into the caller's `*Invalid { reason }` field so the author's
19492/// remediation prose (which specific violation — length / boundary /
19493/// character-class) flows through unchanged.
19494///
19495/// The eight existing call sites — [`crate::AplicacaoSpec`]'s five
19496/// name-shaped slots (`validate_membro_caixa` on `:membros :caixa`,
19497/// `validate_placement_cluster` on `:placement :clusters`,
19498/// `validate_placement_affinity` on `:placement :affinity`,
19499/// `validate_contrato_caixa` on `:contratos :de`/`:para`,
19500/// `validate_entrada_para` on `:entrada :para`),
19501/// [`crate::SupervisorSpec::validate`] on `:children :caixa`,
19502/// [`crate::manifest::Caixa::validate_nome`] on `:nome`, and
19503/// [`crate::upgrade::validate_module`] on `:upgrade-from :module` —
19504/// each formerly inlined this two-arm cascade verbatim. Lifting to one
19505/// canonical entry-point closes the drift footgun structurally: a
19506/// future widening of the accepted DNS-1123-label shape (a hypothetical
19507/// IDN-Punycode-accepting variant, a per-axis strictness override for
19508/// the M4 CR materializer's `spec.name` axes, or the future
19509/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's admission
19510/// webhook floor) reaches every name-shaped consumer by one edit at
19511/// this helper, not a coordinated rewrite across three modules.
19512///
19513/// Peer of [`require_valid_versao_requirement`] on the same closure-
19514/// based caller-error-variant discipline — the caller owns the enum
19515/// variant + its self-locating discriminator fields (`caixa`, `cluster`,
19516/// `affinity`, `nome`, `slot`, `kind`, `module`, …), this helper only
19517/// sequences the two gate arms in canonical order and threads the
19518/// predicate's shape-shaped reason into the invalid arm's `reason:`
19519/// field.
19520///
19521/// # Errors
19522///
19523/// Returns `on_empty()` for `value.is_empty()`; returns
19524/// `on_invalid(reason)` when [`is_dns_1123_label`] rejects the
19525/// non-empty input (the predicate's parser-shaped reason threaded
19526/// through as the invalid arm's `reason:`); returns `Ok(())` otherwise.
19527pub fn require_valid_dns_1123_label<E>(
19528    value: &str,
19529    on_empty: impl FnOnce() -> E,
19530    on_invalid: impl FnOnce(String) -> E,
19531) -> Result<(), E> {
19532    if value.is_empty() {
19533        return Err(on_empty());
19534    }
19535    if let Err(reason) = is_dns_1123_label(value) {
19536        return Err(on_invalid(reason));
19537    }
19538    Ok(())
19539}
19540
19541/// Bracket a sandboxed-relative `.lisp`-terminating path axis with the
19542/// shared "empty → absolute → parent-escape → non-`.lisp`-extension"
19543/// four-arm gate every author-supplied M2 tatara-lisp source-path slot
19544/// on the caixa surface carries. Delegates to
19545/// [`is_sandboxed_relative_path`] for the three structural arms and to
19546/// [`is_lisp_extension`] for the extension arm; returns each arm's
19547/// caller-owned error variant via the four `FnOnce` closures.
19548///
19549/// The arm ordering (`Empty → Absolute → ParentEscape → NonLisp`) is
19550/// canonical across every existing per-axis site — a path that is
19551/// *both* sandbox-escaping and non-`.lisp` surfaces the more
19552/// fundamental sandbox-shape diagnostic first (the `.lisp` remediation
19553/// would be misleading when the offending path can never resolve under
19554/// the caixa root anyway; the canonical fix collapses both into "pin a
19555/// relative `.lisp` path under the caixa root"). Same
19556/// smallest-scope-arm-fires-last posture the peer
19557/// [`require_positive_bounded_u32`] /
19558/// [`require_positive_canonical_bounded_duration`] chains follow on the
19559/// integer / duration axes, and the same posture every per-axis inline
19560/// pre-lift block already applied by hand
19561/// ([`crate::behavior::BehaviorError`]'s `EmptyPath` → `AbsolutePath`
19562/// → `ParentEscape` → `NonLispExtension` chain,
19563/// [`crate::upgrade::UpgradeError`]'s `EmptyScript` → `AbsoluteScript`
19564/// → `ParentEscapeScript` → `NonLispExtensionScript` chain).
19565///
19566/// Two identical-shape call sites collapse onto this helper — one for
19567/// each M2 typed path-slot the wasm-engine reads through
19568/// `tatara_lisp::read`:
19569///
19570///   * [`crate::behavior::BehaviorSpec::validate`] on
19571///     `:behavior :on-*` callback paths — every arm carries the slot
19572///     name verbatim through the closure's caller-side capture (empty
19573///     → [`crate::behavior::BehaviorError::EmptyPath`], absolute →
19574///     [`crate::behavior::BehaviorError::AbsolutePath`], parent-escape
19575///     → [`crate::behavior::BehaviorError::ParentEscape`], non-`.lisp`
19576///     → [`crate::behavior::BehaviorError::NonLispExtension`]);
19577///   * [`crate::upgrade::UpgradeInstruction::validate`]'s `StateChange`
19578///     arm on `:upgrade-from :state-change :script` (empty →
19579///     [`crate::upgrade::UpgradeError::EmptyScript`], absolute →
19580///     [`crate::upgrade::UpgradeError::AbsoluteScript`], parent-escape
19581///     → [`crate::upgrade::UpgradeError::ParentEscapeScript`],
19582///     non-`.lisp` →
19583///     [`crate::upgrade::UpgradeError::NonLispExtensionScript`]).
19584///
19585/// Peer of the sibling `require_positive_bounded_u32` /
19586/// `require_positive_bounded_u64` /
19587/// `require_positive_canonical_bounded_duration` /
19588/// `require_valid_versao_requirement` / `require_valid_dns_1123_label`
19589/// helpers on the same closure-based caller-error-variant discipline —
19590/// the caller owns the enum variant + its self-locating discriminator
19591/// fields (`slot`, `path`, `script`), this helper only sequences the
19592/// four gate arms in canonical order and invokes the caller's closure
19593/// on the offending arm.
19594///
19595/// PRIME DIRECTIVE promotion: the two-consumer duplication budget
19596/// (THEORY.md §I.3.5: "every recurring shape becomes a generator
19597/// before it becomes a pattern; every pattern becomes a library before
19598/// it becomes duplicated code. The duplication budget is zero.")
19599/// promotes the four-step cascade to a typed substrate-side helper on
19600/// the same trajectory the [`is_sandboxed_relative_path`] /
19601/// [`is_lisp_extension`] primitives already follow. A future third
19602/// consumer — the `:bibliotecas` per-entry tatara-lisp source-file
19603/// axis, the `:exe` `:kind Binario` entry-point axis, the M2.5
19604/// wasm-engine pre-warm hook axis, the future `mesh.pleme.io/v1alpha1/Caixa`
19605/// CR materializer's per-path validator — lands as a thin
19606/// four-closure wrapper rather than re-inlining the same four-arm
19607/// cascade.
19608///
19609/// # Errors
19610///
19611/// Returns `on_empty()` when `path` is empty; returns `on_absolute()`
19612/// when `path` is absolute; returns `on_parent_escape()` when `path`
19613/// carries a [`std::path::Component::ParentDir`] component anywhere;
19614/// returns `on_non_lisp()` when `path`'s terminating extension is not
19615/// exactly [`LISP_SOURCE_EXTENSION`]; returns `Ok(())` otherwise.
19616pub fn require_sandboxed_lisp_path<E>(
19617    path: &Path,
19618    on_empty: impl FnOnce() -> E,
19619    on_absolute: impl FnOnce() -> E,
19620    on_parent_escape: impl FnOnce() -> E,
19621    on_non_lisp: impl FnOnce() -> E,
19622) -> Result<(), E> {
19623    match is_sandboxed_relative_path(path) {
19624        Ok(()) => {}
19625        Err(PathShapeViolation::Empty) => return Err(on_empty()),
19626        Err(PathShapeViolation::Absolute) => return Err(on_absolute()),
19627        Err(PathShapeViolation::ParentEscape) => return Err(on_parent_escape()),
19628    }
19629    if !is_lisp_extension(path) {
19630        return Err(on_non_lisp());
19631    }
19632    Ok(())
19633}
19634
19635/// Bracket a per-list uniqueness gate with the shared "insert into
19636/// `seen`; caller-shaped `Err` on the second occurrence" gate every
19637/// declaration-order-preserving `Vec`-authored slot in caixa-core
19638/// carries. Delegates to [`std::collections::HashSet::insert`] verbatim
19639/// (which returns `true` on first insertion, `false` on repeat), then
19640/// invokes the caller's `on_duplicate` closure only on the duplicate
19641/// arm — keeping the hot path (the unique case) allocation-free.
19642///
19643/// The ten existing call sites — [`crate::AplicacaoSpec::validate`]'s
19644/// four per-list uniqueness gates (`:membros :caixa` →
19645/// [`crate::AplicacaoError::MembroDuplicate`], `:placement :clusters` →
19646/// [`crate::AplicacaoError::PlacementClusterDuplicate`],
19647/// `:entrada :paths` → [`crate::AplicacaoError::EntradaPathDuplicate`],
19648/// `:contratos` on the six-tuple typed-edge identity key →
19649/// [`crate::AplicacaoError::ContratoDuplicate`]),
19650/// [`crate::SupervisorSpec::validate`] on `:children :caixa`
19651/// ([`crate::SupervisorError::DuplicateChildCaixa`]),
19652/// [`crate::manifest::Caixa`]'s four per-list uniqueness gates
19653/// ([`crate::manifest::Caixa::validate_deps`] on `:deps` and `:deps-dev`
19654/// → [`crate::DepError::DuplicateNome`],
19655/// [`crate::manifest::Caixa::validate_code_paths`] on
19656/// `:bibliotecas`/`:exe`/`:servicos` →
19657/// [`crate::ManifestError::CodePathDuplicate`],
19658/// [`crate::manifest::Caixa::validate_etiquetas`] on `:etiquetas` →
19659/// [`crate::ManifestError::EtiquetaDuplicate`],
19660/// [`crate::manifest::Caixa::validate_autores`] on `:autores` →
19661/// [`crate::ManifestError::AutorDuplicate`]), and
19662/// [`crate::dep::Dep`]'s [`crate::DepError::CaracteristicaDuplicate`]
19663/// gate on `:caracteristicas` — each formerly inlined the same three-
19664/// line
19665/// ```ignore
19666/// if !seen.insert(key) {
19667///     return Err(<Variant> { … });
19668/// }
19669/// ```
19670/// shape by hand, differing only in the seen-set key type and the
19671/// caller's [`thiserror`] variant. Lifting to one canonical entry-point
19672/// closes the drift footgun structurally: a future tightening of the
19673/// per-list uniqueness discipline (a declaration-order pin on the
19674/// reported entry index, an instrumentation hook for the operator's
19675/// audit trail, the M4 CR materializer's admission-webhook per-list
19676/// invariant) reaches every consumer by one edit at this helper, not
19677/// a coordinated rewrite across every per-list gate in the crate. The
19678/// per-axis error variants remain the source of truth for each axis's
19679/// remediation prose — this helper only sequences the insert-and-check
19680/// pair.
19681///
19682/// Same set-not-multiset discipline every peer `Duplicate*` variant
19683/// documents. The typed key `K` is generic so both `&str`-shaped
19684/// callers (nine sites) and the tuple-shaped
19685/// [`crate::AplicacaoError::ContratoDuplicate`] typed-edge identity
19686/// carrier route through one helper; the caller owns the enum variant
19687/// + its self-locating discriminator fields, this helper only sequences
19688/// the insert-and-check pair in canonical `insert → on_duplicate` order.
19689/// Sibling to the peer `require_positive_bounded_*` /
19690/// `require_positive_canonical_bounded_duration` /
19691/// `require_valid_versao_requirement` / `require_valid_dns_1123_label`
19692/// helpers on the same closure-based caller-error-variant discipline.
19693///
19694/// # Errors
19695///
19696/// Returns `on_duplicate()` when `key` was already in `seen` (the
19697/// [`std::collections::HashSet::insert`] call returns `false`); returns
19698/// `Ok(())` otherwise.
19699pub fn insert_first_seen<K, E, S>(
19700    seen: &mut std::collections::HashSet<K, S>,
19701    key: K,
19702    on_duplicate: impl FnOnce() -> E,
19703) -> Result<(), E>
19704where
19705    K: std::hash::Hash + Eq,
19706    S: std::hash::BuildHasher,
19707{
19708    if seen.insert(key) {
19709        Ok(())
19710    } else {
19711        Err(on_duplicate())
19712    }
19713}
19714
19715/// Test-side pin that asserts a renderer-crate `pub use caixa_core::X;`
19716/// re-export shares both the byte value *and* the `&'static str`
19717/// allocation of its canonical `caixa_core::X` declaration — the
19718/// stronger predicate than a plain `assert_eq!` byte-equality check.
19719///
19720/// The canonical drift footgun this closes: a renderer crate silently
19721/// carries a sibling `pub const X: &str = "…";` (or a copy-pasted
19722/// `pub const X: &str = caixa_core::X;` shape whose right-hand side
19723/// materializes a fresh promoted-static allocation with the same
19724/// bytes) instead of `pub use caixa_core::X;`. A byte-only `assert_eq!`
19725/// on the value would pass — the strings are equal — but the two
19726/// declarations point at two different `&'static` allocations, so a
19727/// future canonical-side rebrand (`caixa_core::X` migrates from
19728/// `"foo"` to `"foo-v2"`) silently drifts the two apart, with the
19729/// apply-time symptom (the cluster-side CRD schema drops the malformed
19730/// axis, the operator's dispatch loop misses the renamed key, the
19731/// Cilium data plane silently reroutes past the renamed L4/L7 rule)
19732/// far from the drift commit's source. Byte-equality misses this
19733/// class of drift; static-data identity via [`std::ptr::eq`] catches
19734/// it structurally.
19735///
19736/// Lifted from the seventy-five per-`_re_export_points_at_caixa_core_
19737/// canonical` test bodies formerly inlined verbatim across
19738/// [`caixa-mesh`][mesh] (49 tests), [`caixa-flux`][flux] (21 tests),
19739/// and [`caixa-helm`][helm] (5 tests) — each formerly carried the same
19740/// two-arm `assert_eq!(<LOCAL>, caixa_core::<LOCAL>);` + `assert!(std
19741/// ::ptr::eq(<LOCAL>.as_ptr(), caixa_core::<LOCAL>.as_ptr()), "…must
19742/// be a re-export of caixa_core::…, not a sibling `pub const`…");`
19743/// pair by hand, differing only in the local `<LOCAL>` identifier the
19744/// diagnostic names. The lifted helper puts the canonical two-arm
19745/// gate in exactly one place so the next per-renderer re-export pin
19746/// (the future [`caixa-otel`] telemetry-pipeline renderer's per-CR
19747/// axis re-exports, the M4 [`mesh.pleme.io/v1alpha1/Aplicacao`] CR
19748/// materializer's per-spec-axis re-exports, the future per-Supervisor
19749/// reconciler's per-`:children` axis re-exports) lands on this
19750/// helper by construction rather than by copying the boilerplate.
19751///
19752/// Same trajectory as the sibling [`require_kind`] /
19753/// [`require_single_servico`] cross-renderer-shared-gate lifts on the
19754/// production-side axis; this closes the peer test-side re-export-
19755/// identity-gate axis.
19756///
19757/// # Panics
19758///
19759/// Panics via [`assert_eq!`] when the two byte-strings differ; panics
19760/// via [`assert!`] on the [`std::ptr::eq`] arm when the two share
19761/// bytes but point at different `&'static str` allocations. The
19762/// `name` argument names the local re-export for the failure message
19763/// so the diagnostic reads `KUBE_KEY_SPEC must be a re-export of
19764/// caixa_core::KUBE_KEY_SPEC, …` — pointing at the offending
19765/// re-export site, not just at the assertion.
19766///
19767/// [mesh]: https://docs.rs/caixa-mesh
19768/// [flux]: https://docs.rs/caixa-flux
19769/// [helm]: https://docs.rs/caixa-helm
19770pub fn assert_str_reexport_identity(name: &str, local: &'static str, canonical: &'static str) {
19771    assert_eq!(
19772        local, canonical,
19773        "{name} must byte-equal caixa_core::{name}"
19774    );
19775    assert!(
19776        std::ptr::eq(local.as_ptr(), canonical.as_ptr()),
19777        "{name} must be a re-export of caixa_core::{name}, \
19778         not a sibling `pub const` that happens to carry the same string \
19779         — drift between the two is the canonical footgun this lift closes"
19780    );
19781}
19782
19783/// Extension methods on [`serde_yaml::Mapping`] that lift the per-key
19784/// scalar-promotion boilerplate every K8s-artifact-emitter across
19785/// `caixa-mesh`, `caixa-flux`, `caixa-helm`, and `caixa-core::render`
19786/// carries: the canonical `mapping.insert(Value::String(key.into()),
19787/// value)` three-liner the schema-key axis of every emitted YAML
19788/// document tunnels a `&'static str` key axis-name through.
19789///
19790/// Five methods form the primitive quintuple — one per non-Null
19791/// primitive [`serde_yaml::Value`] variant the K8s-artifact-emit
19792/// surface actually reaches for as a leaf payload:
19793///
19794///   * [`Self::insert_str_key`] — insert with a `&str` key and any
19795///     fully-built [`serde_yaml::Value`]. The building block every
19796///     other renderer helper (`yaml_string_mapping`, `label_selector`,
19797///     `kube_resource_skeleton`, `single_field_overlay`) composes on
19798///     top of.
19799///   * [`Self::insert_string`] — insert with a `&str` key and an
19800///     `Into<String>` value that gets auto-promoted to
19801///     [`serde_yaml::Value::String`]. The string-scalar-valued-field
19802///     shape every schema-typed `apiVersion` / `kind` /
19803///     `metadata.namespace` / `port.protocol` / `hostname` /
19804///     `path.value` axis emission uses — collapses the two-step
19805///     `insert_str_key(K, Value::String(V.into()))` boilerplate onto
19806///     one direct call.
19807///   * [`Self::insert_number`] — insert with a `&str` key and an
19808///     `Into<serde_yaml::Number>` value that gets auto-promoted to
19809///     [`serde_yaml::Value::Number`]. The integer-scalar-valued-field
19810///     shape every schema-typed `port` / `targetPort` / `attempts` /
19811///     `maxFailures` / `hostPort` axis emission uses — collapses the
19812///     two-step `insert_str_key(K, Value::Number(N.into()))`
19813///     boilerplate onto one direct call.
19814///   * [`Self::insert_mapping`] — insert with a `&str` key and a
19815///     [`serde_yaml::Mapping`] value that gets auto-promoted to
19816///     [`serde_yaml::Value::Mapping`]. The nested-Mapping-valued-field
19817///     shape every schema-typed `metadata` / `spec` / `spec.rules[].path`
19818///     / `toPorts[].rules` sub-block emission uses — collapses the
19819///     two-step `insert_str_key(K, Value::Mapping(m))` boilerplate
19820///     onto one direct call.
19821///   * [`Self::insert_sequence`] — insert with a `&str` key and a
19822///     `Vec<serde_yaml::Value>` value that gets auto-promoted to
19823///     [`serde_yaml::Value::Sequence`]. The list-shape-valued-field
19824///     shape every schema-typed `spec.ingress[].fromEndpoints` /
19825///     `spec.ingress[].toPorts` / `spec.hostnames` / `spec.rules` list
19826///     emission uses — collapses the two-step
19827///     `insert_str_key(K, Value::Sequence(v))` boilerplate onto one
19828///     direct call.
19829///
19830/// A sibling method — [`Self::entry_str_key`] — closes the entry-API
19831/// twin of [`Self::insert_str_key`] on the same `&str →  Value::String`
19832/// key-promotion axis: the [`serde_yaml::Mapping::entry`] method's
19833/// `Value` parameter demands the same `Value::String(<K>.into())`
19834/// wrapping every fresh-emit site's `insert_str_key` call closes, but
19835/// on the idempotent-upsert axis (where callers compose
19836/// `.or_insert(...)` / `.or_insert_with(...)` / `.and_modify(...)` /
19837/// `.or_default()` on the returned entry handle) rather than the
19838/// fresh-emit axis. Same key-promotion contract, different downstream
19839/// API surface — so a future rebrand of the promotion (e.g. to
19840/// [`serde_yaml::Value::Tagged`] under a K8s Server-Side-Apply typed-
19841/// field-ownership axis) reaches both fresh-emit and upsert sites
19842/// through one lift.
19843///
19844/// See each method's docstring for its compounding rationale.
19845pub trait MappingExt {
19846    /// Insert `(key, value)` into `self` with `key` promoted to a
19847    /// [`serde_yaml::Value::String`]. Returns the prior value at that
19848    /// key, mirroring [`serde_yaml::Mapping::insert`].
19849    ///
19850    /// The canonical shape ~48 call sites across the caixa-side
19851    /// renderer surface (`caixa-mesh` per-`CiliumNetworkPolicy` /
19852    /// `Gateway` / `HTTPRoute` construction, `caixa-flux` per-
19853    /// `GitRepository` / `HelmRelease` / `Kustomization` construction,
19854    /// `caixa-helm` per-`Chart.yaml` / `values.yaml` construction,
19855    /// `caixa-core::render` per-skeleton construction) previously
19856    /// carried inline as the three-line block
19857    /// `mapping.insert(serde_yaml::Value::String(<KEY>.into()),
19858    /// <VALUE>)` — three per-call boilerplate axes (`serde_yaml::` path
19859    /// re-quote, `Value::String(_)` promotion, `.into()` `&str → String`
19860    /// coercion) around a two-token semantic payload (`<KEY>`, `<VALUE>`).
19861    ///
19862    /// Lifting collapses the boilerplate into one method call the
19863    /// caller reads as intent (`mapping.insert_str_key(<KEY>, <VALUE>)`
19864    /// — "insert this schema key with this rendered value") rather
19865    /// than five hand-spelled positional artifacts. The next renderer
19866    /// to land — the per-`:politicas` `CiliumClusterwideEnvoyConfig`
19867    /// emitter (MESH-COMPOSITION §III.2 #3), the `app-operator`'s
19868    /// typed `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (§III.2
19869    /// #5), the M4 cross-cluster fan-out's per-cluster `Service` /
19870    /// `HTTPRoute backendRefs` emission, the future `caixa-otel`
19871    /// OpenTelemetry-Collector pipeline emitter — gets the canonical
19872    /// key-scalar-promotion for free with one method call, instead of
19873    /// re-inlining the three-line block.
19874    ///
19875    /// Peer to the sibling render-side helpers on the
19876    /// [`serde_yaml::Value`]-construction surface:
19877    /// [`yaml_string_mapping`] (string→string mapping), [`label_selector`]
19878    /// (K8s `LabelSelector` shape), [`kube_resource_skeleton`] (K8s
19879    /// `apiVersion`+`kind`+`metadata` skeleton), [`single_field_overlay`]
19880    /// (`Option<T>` → single-key overlay). Each closes a distinct axis
19881    /// of the K8s-artifact-emit surface's "same shape, written N times"
19882    /// duplication; this one closes the per-key insert primitive the
19883    /// other four all compose on top of.
19884    fn insert_str_key(&mut self, key: &str, value: serde_yaml::Value) -> Option<serde_yaml::Value>;
19885
19886    /// Insert `(key, Value::String(value.into()))` into `self` — the
19887    /// string-scalar-valued-field emission shape that combines
19888    /// [`Self::insert_str_key`]'s `&str →  Value::String` key promotion
19889    /// with an automatic `Value::String` promotion of an `Into<String>`
19890    /// value. Returns the prior value at that key, mirroring
19891    /// [`serde_yaml::Mapping::insert`].
19892    ///
19893    /// The canonical shape ~17 production call sites across the caixa-
19894    /// side renderer surface previously carried inline as the three-
19895    /// line block `mapping.insert_str_key(<KEY>,
19896    /// serde_yaml::Value::String(<VALUE>.into() | .clone() |
19897    /// .to_string()))` — the two-token semantic payload (`<KEY>`,
19898    /// `<VALUE>`) buried under three boilerplate axes (`serde_yaml::`
19899    /// path re-quote, `Value::String(_)` promotion, the
19900    /// `.into() | .clone() | .to_string()` `→ String` coercion).
19901    ///
19902    /// Sites lifted:
19903    ///
19904    ///   * caixa-mesh's `programs_for_aplicacao` per-`:membros` entry
19905    ///     (`FLEET_PROGRAMS_KEY_NAME` / `FLEET_PROGRAMS_KEY_VERSAO` /
19906    ///     `FLEET_PROGRAMS_KEY_APLICACAO`);
19907    ///   * caixa-mesh's `cilium_network_policies` per-`toPorts[]` port
19908    ///     entry (`KUBE_KEY_PORT` / `KUBE_KEY_PROTOCOL`) and per-HTTP-
19909    ///     rule `CILIUM_KEY_PATH` L7 predicate;
19910    ///   * caixa-mesh's `gateway_routes` per-`Gateway` listener block
19911    ///     (`GATEWAY_API_KEY_NAME` /
19912    ///     [`crate::GATEWAY_API_KEY_HOSTNAME`] / `GATEWAY_API_KEY_PROTOCOL`)
19913    ///     and `spec.gatewayClassName`;
19914    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute` `parentRefs[]`
19915    ///     name, per-rule `matches[].path.{type,value}` prefix-match, and
19916    ///     per-rule `backendRefs[].name` backend-target;
19917    ///   * caixa-flux's `programs_yaml_entry` per-entry `name` /
19918    ///     `namespace` axes;
19919    ///   * caixa-core `kube_resource_skeleton`'s `apiVersion` / `kind`
19920    ///     scalar heads (the two production emit sites the prior
19921    ///     `Value::String(_.to_string())` inline shape sat at).
19922    ///
19923    /// Lifting collapses the boilerplate into one method call the
19924    /// caller reads as intent (`mapping.insert_string(<KEY>, <VALUE>)`
19925    /// — "insert a string-scalar-typed field named `KEY` with rendered
19926    /// value `VALUE`") rather than four hand-spelled positional
19927    /// artifacts. The next renderer to land — the per-`:politicas`
19928    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy string-
19929    /// scalar axes are `name` / `namespace` / `defaultAction`), the
19930    /// `app-operator`'s typed `mesh.pleme.io/v1alpha1/Aplicacao` CR
19931    /// materializer (per-`spec.selectors[]` `name` / per-`spec.gates[]`
19932    /// string-typed axes), the M4 cross-cluster fan-out's per-cluster
19933    /// `Service.spec.ports[].name` / `HTTPRoute.spec.rules[].filters[].
19934    /// requestHeaderModifier.set[].name` string-scalar emission, the
19935    /// future `caixa-otel` OpenTelemetry-Collector `pipelines.traces.
19936    /// receivers[].endpoint` string-scalar emission — gets the canonical
19937    /// string-scalar-valued-field shape for free with one method call,
19938    /// instead of re-inlining the three-token
19939    /// `Value::String(_.into() | .clone() | .to_string())` block.
19940    ///
19941    /// Peer to [`Self::insert_str_key`] on the sibling any-Value axis —
19942    /// the two together form the "one method call per emission axis"
19943    /// primitive pair the K8s-artifact-emit surface's "same shape,
19944    /// written N times" duplication (THEORY.md §I.3.5) collapses onto.
19945    fn insert_string<V: Into<String>>(&mut self, key: &str, value: V) -> Option<serde_yaml::Value>;
19946
19947    /// Insert `(key, Value::Number(value.into()))` into `self` — the
19948    /// integer-scalar-valued-field emission shape that combines
19949    /// [`Self::insert_str_key`]'s `&str → Value::String` key promotion
19950    /// with an automatic [`serde_yaml::Value::Number`] promotion of an
19951    /// `Into<serde_yaml::Number>` value. Returns the prior value at that
19952    /// key, mirroring [`serde_yaml::Mapping::insert`].
19953    ///
19954    /// The canonical shape 2 production call sites across `caixa-mesh`
19955    /// previously carried inline as the three-token block
19956    /// `mapping.insert_str_key(<KEY>, serde_yaml::Value::Number(<N>.into()))`
19957    /// — the two-token semantic payload (`<KEY>`, `<N>`) buried under
19958    /// three boilerplate axes (`serde_yaml::` path re-quote,
19959    /// `Value::Number(_)` promotion, the `<N>.into()` typed-integer →
19960    /// [`serde_yaml::Number`] coercion) around a numeric constant or
19961    /// typed field the caller already carries as `u16` / `u32` / `u64`.
19962    ///
19963    /// Sites lifted:
19964    ///
19965    ///   * caixa-mesh's `gateway_routes` per-`Gateway` `spec.listeners[].port`
19966    ///     external HTTP listener port (`KUBE_KEY_PORT` around the lifted
19967    ///     [`crate::GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`] `u16` const,
19968    ///     cd60fde);
19969    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute.spec.rules[].backendRefs[].port`
19970    ///     backend-target Servico port (`KUBE_KEY_PORT` around the
19971    ///     [`crate::AplicacaoSpec`]-side `entrada.port` `u16` field the
19972    ///     `:entrada :port` typed slot flows through).
19973    ///
19974    /// Lifting collapses the boilerplate into one method call the
19975    /// caller reads as intent (`mapping.insert_number(<KEY>, <N>)` —
19976    /// "insert a numeric-scalar-typed field named `KEY` with the typed
19977    /// integer `N`") rather than three hand-spelled positional artifacts.
19978    /// The next renderer to land — the per-`:politicas`
19979    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy
19980    /// integer-scalar axes are the Envoy circuit-breaker
19981    /// `maxRequests` / `maxPendingRequests` / `maxConnections` count
19982    /// fields and the Cilium ratelimit `requestPerUnit` field,
19983    /// MESH-COMPOSITION §III.2 #3), the `app-operator`'s typed
19984    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (per-`spec.
19985    /// selectors[]` integer-scored `weight` fields, §III.2 #5), the
19986    /// M4 cross-cluster fan-out's per-cluster
19987    /// `Service.spec.ports[].{port, targetPort, nodePort}` /
19988    /// `HTTPRoute.spec.rules[].backendRefs[].{port, weight}`
19989    /// integer-scalar emission, the future `caixa-otel`
19990    /// OpenTelemetry-Collector `service.pipelines.traces.receivers[].
19991    /// grpc.max_recv_msg_size_mib` integer-scalar emission — gets the
19992    /// canonical integer-scalar-valued-field shape for free with one
19993    /// method call, instead of re-inlining the three-token
19994    /// `Value::Number(_.into())` block.
19995    ///
19996    /// The `Into<serde_yaml::Number>` bound accepts every numeric
19997    /// primitive [`serde_yaml::Number`] declares `From` for
19998    /// (`i8`..=`i64`, `u8`..=`u64`, `f32`, `f64`) — the same coverage
19999    /// the two production sites reach through with their `u16` port
20000    /// fields and the same coverage every future numeric-scalar
20001    /// emission (the K8s `Service.spec.ports[].targetPort` `IntOrString`
20002    /// integer arm, the `HTTPRoute.spec.rules[].backendRefs[].weight`
20003    /// `int32` axis, the Envoy `maxRequests` `uint32` axis) reaches
20004    /// through with matching typed integer fields.
20005    ///
20006    /// Peer to [`Self::insert_string`] on the sibling string-scalar axis
20007    /// and to [`Self::insert_mapping`] / [`Self::insert_sequence`] on
20008    /// the sibling nested-Mapping / list-shape axes — the five together
20009    /// with [`Self::insert_str_key`] form the "one method call per
20010    /// emission axis" primitive quintuple the K8s-artifact-emit
20011    /// surface's "same shape, written N times" duplication (THEORY.md
20012    /// §I.3.5) collapses onto: `insert_str_key` for any-Value inserts,
20013    /// `insert_string` for the string-scalar-valued-field shape,
20014    /// `insert_number` for the integer-scalar-valued-field shape,
20015    /// `insert_mapping` for the nested-Mapping-valued-field shape,
20016    /// `insert_sequence` for the list-shape-valued-field shape.
20017    fn insert_number<N: Into<serde_yaml::Number>>(
20018        &mut self,
20019        key: &str,
20020        value: N,
20021    ) -> Option<serde_yaml::Value>;
20022
20023    /// Insert `(key, Value::Mapping(value))` into `self` — the
20024    /// nested-Mapping-valued-field emission shape that combines
20025    /// [`Self::insert_str_key`]'s `&str →  Value::String` key promotion
20026    /// with an automatic [`serde_yaml::Value::Mapping`] promotion of a
20027    /// [`serde_yaml::Mapping`] value. Returns the prior value at that
20028    /// key, mirroring [`serde_yaml::Mapping::insert`].
20029    ///
20030    /// The canonical shape ~6 production call sites across the caixa-
20031    /// side renderer surface previously carried inline as the three-
20032    /// token block `mapping.insert_str_key(<KEY>,
20033    /// serde_yaml::Value::Mapping(<INNER>))` — a two-token semantic
20034    /// payload (`<KEY>`, `<INNER>`) buried under a two-axis boilerplate
20035    /// (`serde_yaml::` path re-quote, `Value::Mapping(_)` promotion)
20036    /// around a `Mapping` variable the caller already built.
20037    ///
20038    /// Sites lifted:
20039    ///
20040    ///   * caixa-mesh's `cilium_network_policies` per-`toPorts[]`
20041    ///     `rules:` L7-introspection sub-block (`KUBE_KEY_RULES` around
20042    ///     the built `rules` Mapping);
20043    ///   * caixa-mesh's `cilium_network_policies` per-`CiliumNetworkPolicy`
20044    ///     `spec:` block (`KUBE_KEY_SPEC` around the built `policy_spec`
20045    ///     Mapping);
20046    ///   * caixa-mesh's `gateway_routes` per-`Gateway` `spec:` block
20047    ///     (`KUBE_KEY_SPEC` around the built `g_spec` Mapping);
20048    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute.spec.rules[]`
20049    ///     `matches[].path:` sub-block (`GATEWAY_API_KEY_PATH` around the
20050    ///     built `path_match` Mapping);
20051    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute` `spec:` block
20052    ///     (`KUBE_KEY_SPEC` around the built `r_spec` Mapping);
20053    ///   * caixa-core's `kube_resource_skeleton` per-CR
20054    ///     `metadata:` sub-block (`KUBE_KEY_METADATA` around the built
20055    ///     `metadata_map` Mapping).
20056    ///
20057    /// Lifting collapses the boilerplate into one method call the
20058    /// caller reads as intent (`mapping.insert_mapping(<KEY>, <INNER>)`
20059    /// — "insert a nested-Mapping-typed sub-block named `KEY` with the
20060    /// built inner `INNER`") rather than three hand-spelled positional
20061    /// artifacts. The next renderer to land — the per-`:politicas`
20062    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy
20063    /// nested-Mapping sub-blocks are `metadata:` / `spec:` /
20064    /// `spec.resources[]`), the `app-operator`'s typed
20065    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer
20066    /// (per-`spec.selectors[]` and per-`spec.gates[]` sub-blocks), the
20067    /// M4 cross-cluster fan-out's per-cluster `Service.spec` /
20068    /// `HTTPRoute.spec` sub-block emission, the future `caixa-otel`
20069    /// OpenTelemetry-Collector per-pipeline `receivers:` /
20070    /// `processors:` / `exporters:` nested-Mapping emission — gets the
20071    /// canonical nested-Mapping-valued-field shape for free with one
20072    /// method call, instead of re-inlining the three-token
20073    /// `Value::Mapping(_)` promotion.
20074    ///
20075    /// Peer to [`Self::insert_string`] on the sibling scalar-value axis
20076    /// and [`Self::insert_sequence`] on the sibling list-shape axis —
20077    /// the four together with [`Self::insert_str_key`] form the "one
20078    /// method call per emission axis" primitive quadruple the K8s-
20079    /// artifact-emit surface's "same shape, written N times" duplication
20080    /// (THEORY.md §I.3.5) collapses onto: `insert_str_key` for any-Value
20081    /// inserts, `insert_string` for the string-scalar-valued-field
20082    /// shape, `insert_mapping` for the nested-Mapping-valued-field
20083    /// shape, `insert_sequence` for the list-shape-valued-field shape.
20084    fn insert_mapping(
20085        &mut self,
20086        key: &str,
20087        value: serde_yaml::Mapping,
20088    ) -> Option<serde_yaml::Value>;
20089
20090    /// Insert `(key, Value::Sequence(value))` into `self` — the
20091    /// list-shape-valued-field emission shape that combines
20092    /// [`Self::insert_str_key`]'s `&str → Value::String` key promotion
20093    /// with an automatic [`serde_yaml::Value::Sequence`] promotion of a
20094    /// pre-built `Vec<serde_yaml::Value>` value. Returns the prior
20095    /// value at that key, mirroring [`serde_yaml::Mapping::insert`].
20096    ///
20097    /// The canonical shape 4 production call sites across `caixa-mesh`
20098    /// previously carried inline as the three-token block
20099    /// `mapping.insert_str_key(<KEY>, serde_yaml::Value::Sequence(<VEC>))`
20100    /// — a two-token semantic payload (`<KEY>`, `<VEC>`) buried under a
20101    /// two-axis boilerplate (`serde_yaml::` path re-quote,
20102    /// `Value::Sequence(_)` promotion) around a `Vec<Value>` variable
20103    /// the caller already built.
20104    ///
20105    /// Sites lifted:
20106    ///
20107    ///   * caixa-mesh's `cilium_network_policies` per-`CiliumNetworkPolicy`
20108    ///     `spec.ingress[].fromEndpoints:` singleton-list (`CILIUM_KEY_FROM_ENDPOINTS`
20109    ///     around a `vec![from_endpoint]` selector wrapper);
20110    ///   * caixa-mesh's `cilium_network_policies` per-`CiliumNetworkPolicy`
20111    ///     `spec.ingress[].toPorts:` list (`CILIUM_KEY_TO_PORTS` around the
20112    ///     built `to_ports_seq` per-edge port-and-L7-rule vec);
20113    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute` `spec.hostnames:`
20114    ///     singleton-list (`GATEWAY_API_KEY_HOSTNAMES` around a
20115    ///     `vec![Value::String(entrada.host…)]` host wrapper);
20116    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute` `spec.rules:`
20117    ///     list (`KUBE_KEY_RULES` around the built `rules` per-path
20118    ///     match+backend+overlay vec).
20119    ///
20120    /// Lifting collapses the boilerplate into one method call the
20121    /// caller reads as intent (`mapping.insert_sequence(<KEY>, <VEC>)`
20122    /// — "insert a list-shape-typed sub-block named `KEY` with the built
20123    /// inner `VEC`") rather than three hand-spelled positional
20124    /// artifacts. The next renderer to land — the per-`:politicas`
20125    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy
20126    /// list-shape sub-blocks are `spec.resources[]` / `spec.listeners[]`
20127    /// / `spec.virtualHosts[]`, MESH-COMPOSITION §III.2 #3), the
20128    /// `app-operator`'s typed `mesh.pleme.io/v1alpha1/Aplicacao` CR
20129    /// materializer (per-`spec.selectors[]` and per-`spec.gates[]`
20130    /// list-shape sub-blocks, §III.2 #5), the M4 cross-cluster fan-out's
20131    /// per-cluster `Service.spec.ports[]` /
20132    /// `HTTPRoute.spec.rules[].backendRefs[]` list emission, the future
20133    /// `caixa-otel` OpenTelemetry-Collector per-pipeline `receivers[]`
20134    /// / `processors[]` / `exporters[]` list emission — gets the
20135    /// canonical list-shape-valued-field shape for free with one method
20136    /// call, instead of re-inlining the three-token `Value::Sequence(_)`
20137    /// promotion.
20138    ///
20139    /// Peer to [`Self::insert_mapping`] on the sibling nested-Mapping
20140    /// axis and [`Self::insert_string`] on the sibling scalar-value axis
20141    /// — the four together with [`Self::insert_str_key`] form the "one
20142    /// method call per emission axis" primitive quadruple the K8s-
20143    /// artifact-emit surface's "same shape, written N times" duplication
20144    /// (THEORY.md §I.3.5) collapses onto: `insert_str_key` for any-Value
20145    /// inserts, `insert_string` for the string-scalar-valued-field
20146    /// shape, `insert_mapping` for the nested-Mapping-valued-field
20147    /// shape, `insert_sequence` for the list-shape-valued-field shape.
20148    ///
20149    /// Complementary to [`singleton_mapping_sequence`] on the peer
20150    /// singleton-list-shape axis: `singleton_mapping_sequence(m)` builds
20151    /// the sole-Mapping-element `Value::Sequence` payload;
20152    /// `insert_sequence(K, v)` inserts an already-built `Vec<Value>`
20153    /// payload under a schema key. A caller composing the two through
20154    /// [`Self::insert_singleton_mapping_sequence`] writes
20155    /// `mapping.insert_singleton_mapping_sequence(K, m)` for the
20156    /// singleton case (the sole element is a fresh Mapping); reach for
20157    /// `mapping.insert_sequence(K, v)` for the multi-element or
20158    /// non-Mapping-element case (the vec is built up per-iteration or
20159    /// wraps a non-Mapping scalar).
20160    fn insert_sequence(
20161        &mut self,
20162        key: &str,
20163        value: Vec<serde_yaml::Value>,
20164    ) -> Option<serde_yaml::Value>;
20165
20166    /// Insert `(key, Value::Sequence(vec![Value::Mapping(value)]))` into
20167    /// `self` — the singleton-Mapping-list-shape-valued-field emission
20168    /// shape that composes [`Self::insert_str_key`]'s
20169    /// `&str → Value::String` key promotion with the
20170    /// [`singleton_mapping_sequence`] helper's singleton-list wrap of a
20171    /// [`serde_yaml::Mapping`] payload. Returns the prior value at that
20172    /// key, mirroring [`serde_yaml::Mapping::insert`].
20173    ///
20174    /// The canonical shape 7 production call sites across `caixa-mesh`
20175    /// previously carried inline as the two-token composition
20176    /// `mapping.insert_str_key(<KEY>, singleton_mapping_sequence(<M>))`
20177    /// — a two-token semantic payload (`<KEY>`, `<M>`) buried under a
20178    /// two-symbol boilerplate (`insert_str_key(_, _)` +
20179    /// `singleton_mapping_sequence(_)`) that fully covers the axis: every
20180    /// site both wraps its per-call `Mapping` as the sole-element list
20181    /// value and inserts it under a schema key on an outer `Mapping`. A
20182    /// rebrand on either half — the outer key-scalar promotion axis
20183    /// migrating to a per-key typed `Value` variant, the singleton-list
20184    /// wrap migrating to a Server-Side-Apply-typed `Value::Tagged`
20185    /// per-CRD-list shape once K8s per-field ownership annotations reach
20186    /// the K8s Gateway API / Cilium NetworkPolicy CRD list schemas —
20187    /// would silently desynchronize one site while leaving the other six
20188    /// on the old shape.
20189    ///
20190    /// Sites lifted:
20191    ///
20192    ///   * caixa-mesh's `cilium_network_policies` per-`toPorts[]` port
20193    ///     entry `ports:` singleton-list (`CILIUM_KEY_PORTS` around the
20194    ///     built `port_entry` Mapping);
20195    ///   * caixa-mesh's `cilium_network_policies` per-`toPorts[]` L7
20196    ///     `rules.http:` singleton-list (`CILIUM_KEY_HTTP` around the
20197    ///     built `http_rule` Mapping);
20198    ///   * caixa-mesh's `cilium_network_policies` per-`CiliumNetworkPolicy`
20199    ///     `spec.ingress:` singleton-list (`CILIUM_KEY_INGRESS` around the
20200    ///     built `ingress_rule` Mapping);
20201    ///   * caixa-mesh's `gateway_routes` per-`Gateway` `spec.listeners:`
20202    ///     singleton-list (`GATEWAY_API_KEY_LISTENERS` around the built
20203    ///     `listener` Mapping);
20204    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute.spec.rules[]`
20205    ///     `matches:` singleton-list (`GATEWAY_API_KEY_MATCHES` around the
20206    ///     built `match_entry` Mapping);
20207    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute.spec.rules[]`
20208    ///     `backendRefs:` singleton-list (`GATEWAY_API_KEY_BACKEND_REFS`
20209    ///     around the built `backend_ref` Mapping);
20210    ///   * caixa-mesh's `gateway_routes` per-`HTTPRoute`
20211    ///     `spec.parentRefs:` singleton-list (`GATEWAY_API_KEY_PARENT_REFS`
20212    ///     around the built `parent_ref` Mapping).
20213    ///
20214    /// Lifting collapses the two-symbol composition into one method call
20215    /// the caller reads as intent (`mapping.insert_singleton_mapping_sequence
20216    /// (<KEY>, <M>)` — "insert a singleton-Mapping-list-shape sub-block
20217    /// named `KEY` wrapping the built inner `M`") rather than two
20218    /// nested calls. Peer to [`Self::insert_sequence`] on the sibling
20219    /// multi-element or non-Mapping-element list-shape axis — the two
20220    /// together partition the list-shape-valued-field emission surface:
20221    /// [`Self::insert_singleton_mapping_sequence`] for the sole-Mapping-
20222    /// element case, [`Self::insert_sequence`] for every other case.
20223    ///
20224    /// The next renderer to land — the per-`:politicas`
20225    /// `CiliumClusterwideEnvoyConfig` emitter (whose singleton
20226    /// `spec.resources:[]` / `spec.listeners:[]` / `spec.virtualHosts:[]`
20227    /// Mapping-element blocks, MESH-COMPOSITION §III.2 #3, are exactly the
20228    /// singleton-Mapping-list shape), the `app-operator`'s typed
20229    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (per-single-
20230    /// selector / per-single-gate emission, §III.2 #5), the M4 cross-
20231    /// cluster fan-out's per-cluster singleton `Service.spec.ports[]` /
20232    /// `HTTPRoute.spec.rules[].backendRefs[]` sole-element emission, the
20233    /// future `caixa-otel` OpenTelemetry-Collector `pipelines.traces.
20234    /// receivers[]` singleton-receiver emission — gets the canonical
20235    /// singleton-Mapping-list-shape wrap+insert for free with one method
20236    /// call, instead of re-inlining the two-symbol composition.
20237    fn insert_singleton_mapping_sequence(
20238        &mut self,
20239        key: &str,
20240        value: serde_yaml::Mapping,
20241    ) -> Option<serde_yaml::Value>;
20242
20243    /// Entry-API sibling of [`Self::insert_str_key`] — mint the
20244    /// `Value::String(<KEY>.into())` key-promotion the underlying
20245    /// [`serde_yaml::Mapping::entry`] method's `Value` parameter
20246    /// demands, and return the entry-API's
20247    /// [`serde_yaml::mapping::Entry`] handle the caller composes
20248    /// `.or_insert(<V>)` / `.or_insert_with(<F>)` /
20249    /// `.and_modify(<F>)` / `.or_default()` on.
20250    ///
20251    /// The canonical shape 4 production call sites across `caixa-flux`
20252    /// previously carried inline as the three-token composition
20253    /// `mapping.entry(serde_yaml::Value::String(<KEY>.into()))` around
20254    /// a one-token semantic payload (the schema key axis-name). Every
20255    /// site immediately composes an `.or_insert(...)` on the returned
20256    /// [`serde_yaml::mapping::Entry`] handle — the pattern is the
20257    /// entry-API twin of the [`Self::insert_str_key`] pattern the
20258    /// ~48 fresh-emit sites already collapsed onto (23506b3).
20259    ///
20260    /// Sites lifted:
20261    ///
20262    ///   * caixa-flux's `programs_yaml_entry` per-`servico_m2_overlay`
20263    ///     key idempotent-upsert loop (`entry.entry(Value::String(
20264    ///     <key>.to_string())).or_insert(<value>)` — one
20265    ///     `.or_insert(...)` per `M2_KEY_LIMITS` / `M2_KEY_BEHAVIOR` /
20266    ///     `M2_KEY_UPGRADE_FROM` axis, iterating the
20267    ///     [`servico_m2_overlay`] `BTreeMap`);
20268    ///   * caixa-flux's `upsert_into_helmrelease_programs` per-
20269    ///     `HelmRelease.spec.values` upsert-if-absent (`FLUX_KEY_VALUES`
20270    ///     around a default fresh `Value::Mapping`);
20271    ///   * caixa-flux's `upsert_into_helmrelease_programs` per-
20272    ///     `HelmRelease.spec.values.programs` upsert-if-absent
20273    ///     (`FLEET_PROGRAMS_KEY_PROGRAMS` around a default fresh
20274    ///     `Value::Sequence`);
20275    ///   * caixa-flux's `upsert_into_programs_yaml` per-top-level
20276    ///     `programs:` upsert-if-absent (`FLEET_PROGRAMS_KEY_PROGRAMS`
20277    ///     around a default fresh `Value::Sequence` — the sibling of
20278    ///     the `upsert_into_helmrelease_programs` site on the same
20279    ///     key, one path deep in a HelmRelease `spec.values.` sub-tree,
20280    ///     one path at the values.yaml root).
20281    ///
20282    /// Lifting collapses the three-token composition into one method
20283    /// call the caller reads as intent
20284    /// (`mapping.entry_str_key(<KEY>).or_insert(<DEFAULT>)` — "get the
20285    /// entry handle for this schema key and default it if missing")
20286    /// rather than four hand-spelled positional artifacts
20287    /// (`serde_yaml::` path re-quote, `Value::String(_)` promotion,
20288    /// the `.into() | .to_string()` `&str → String` coercion, plus the
20289    /// `.entry(_)` call itself). The next renderer to land — the
20290    /// per-`:politicas` `CiliumClusterwideEnvoyConfig` emitter (which
20291    /// upserts singleton `spec.resources:[]` / `spec.listeners:[]`
20292    /// blocks under an existing per-cluster overlay CR, MESH-COMPOSITION
20293    /// §III.2 #3), the `app-operator`'s typed
20294    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (which
20295    /// upserts `status.` sub-fields on partial reconciles, §III.2 #5),
20296    /// the M4 cross-cluster fan-out's per-cluster idempotent
20297    /// HelmRelease upsert — gets the canonical entry-API key-promotion
20298    /// for free with one method call, instead of re-inlining the
20299    /// three-token block.
20300    ///
20301    /// Peer to [`Self::insert_str_key`] on the sibling fresh-emit
20302    /// axis of the same `&str → Value::String` key-promotion — the
20303    /// two together partition the `Mapping`-write surface: entry-API
20304    /// for idempotent-upsert sites where the caller cares whether the
20305    /// prior value was present (`or_insert` / `and_modify` /
20306    /// `or_default` composition), insert-API for fresh-emit sites where
20307    /// the caller unconditionally writes a value and either drops or
20308    /// pattern-matches on the returned `Option<Value>` prior value.
20309    fn entry_str_key(&mut self, key: &str) -> serde_yaml::mapping::Entry<'_>;
20310
20311    /// Arity-0-or-1 twin of [`Self::insert_str_key`] — insert
20312    /// `(key, value.clone())` iff `value` is `Some`; leave `self`
20313    /// untouched iff `value` is `None`. Returns the prior value at that
20314    /// key when the insert fires (mirroring
20315    /// [`serde_yaml::Mapping::insert`]), and `None` otherwise (no insert
20316    /// happened, so no prior value can be surfaced).
20317    ///
20318    /// The canonical shape 3 production call sites across `caixa-mesh`
20319    /// previously carried inline as the three-line block
20320    /// `if let Some(<x>) = &<overlay> { <mapping>.insert_str_key(<KEY>,
20321    /// <x>.clone()); }` around a two-token semantic payload (the schema
20322    /// key axis-name + the `Option<Value>` overlay slot). Every site
20323    /// pairs a per-`:politicas` overlay [`single_field_overlay`] `Option
20324    /// <Value>` output with the same conditional-insert conditional —
20325    /// the arity-0-or-1 twin of [`Self::insert_str_key`]'s always-1
20326    /// arity on the per-`(:de, :para)` axis.
20327    ///
20328    /// Sites lifted:
20329    ///
20330    ///   * caixa-mesh's `cilium_network_policies` per-ingress-rule
20331    ///     `:politicas :mtls-required` mutual-auth overlay
20332    ///     ([`crate::CILIUM_KEY_AUTHENTICATION`] around the
20333    ///     `mtls_overlay` [`single_field_overlay`] output — the
20334    ///     tristate `{mode: required | disabled}` block or the
20335    ///     None-omit arm);
20336    ///   * caixa-mesh's `gateway_routes` per-HTTPRoute-rule
20337    ///     `:politicas :timeout` request-deadline overlay
20338    ///     ([`crate::GATEWAY_API_KEY_TIMEOUTS`] around the
20339    ///     `timeout_overlay` [`single_field_overlay`] output — the
20340    ///     `{request: "<duration>"}` block or the None-omit arm);
20341    ///   * caixa-mesh's `gateway_routes` per-HTTPRoute-rule
20342    ///     `:politicas :retries` retry-attempt-cap overlay
20343    ///     ([`crate::GATEWAY_API_KEY_RETRY`] around the
20344    ///     `retry_overlay` [`single_field_overlay`] output — the
20345    ///     `{attempts: <N>}` block or the None-omit arm).
20346    ///
20347    /// Lifting collapses the three-line block into one method call the
20348    /// caller reads as intent (`mapping.insert_str_key_if_some(<KEY>,
20349    /// <overlay>.as_ref())` — "insert this schema key if the overlay
20350    /// carried a value; else leave the key absent") rather than four
20351    /// hand-spelled positional artifacts (the `if let Some(_) = &_`
20352    /// destructure, the per-inner `.clone()`, the trailing brace, plus
20353    /// the `.insert_str_key(_)` call itself). The absent-overlay arm —
20354    /// which every [`MeshPolicy`] axis defaults to when the author
20355    /// leaves the typed slot unset (the `None` arm of the
20356    /// `Option<Value>` [`single_field_overlay`] output) — reads as the
20357    /// method's own `Option::None` branch, not a per-call-site inverted
20358    /// `if let Some` scaffold around a per-call-site clone.
20359    ///
20360    /// The next renderer to land — the per-`:politicas`
20361    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy
20362    /// `authentication:` / `rateLimit:` / `circuitBreaker:` Option
20363    /// overlays, MESH-COMPOSITION §III.2 #3, thread through the same
20364    /// [`single_field_overlay`] `Option<Value>` axis the three lifted
20365    /// sites here already reach), the `app-operator`'s typed
20366    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (whose per-
20367    /// selector `status.` sub-field overlays are the same arity-0-or-1
20368    /// shape, §III.2 #5), the M4 cross-cluster fan-out's per-cluster
20369    /// `HTTPRoute.spec.rules[].filters[]` per-filter Option overlays
20370    /// (the same shape at the per-cluster axis) — gets the canonical
20371    /// arity-0-or-1 conditional-insert for free with one method call,
20372    /// instead of re-inlining the three-line `if let Some { clone;
20373    /// insert_str_key }` block.
20374    ///
20375    /// Peer to [`Self::insert_str_key`] on the always-1 arity axis
20376    /// (fresh-emit sites where the caller unconditionally writes a
20377    /// value) — the two together partition the fresh-emit surface
20378    /// exactly on the arity axis: [`Self::insert_str_key`] for
20379    /// unconditional writes, [`Self::insert_str_key_if_some`] for
20380    /// conditional writes gated on an `Option<Value>` upstream
20381    /// producer (the per-`:politicas` overlay
20382    /// [`single_field_overlay`] axis, and every future arity-0-or-1
20383    /// axis every future renderer's optional-slot machinery reaches
20384    /// through).
20385    ///
20386    /// The `Option<&Value>` shape (as opposed to an owned
20387    /// `Option<Value>`) lets the caller pass `overlay.as_ref()` on an
20388    /// owned `Option<Value>` the caller reuses across iterations of an
20389    /// outer per-`(:de, :para)` or per-rule loop — every lifted site
20390    /// consumes the overlay from a loop-outer binding into each of N
20391    /// per-iteration `Mapping`s, so the clone happens iff the insert
20392    /// fires (the None arm skips the clone entirely) and the outer
20393    /// binding stays available for the next iteration.
20394    fn insert_str_key_if_some(
20395        &mut self,
20396        key: &str,
20397        value: Option<&serde_yaml::Value>,
20398    ) -> Option<serde_yaml::Value>;
20399
20400    /// Fetch a `&mut serde_yaml::Mapping` at `key`, defaulting an empty
20401    /// [`serde_yaml::Mapping`] into place when the entry is absent.
20402    /// Returns `Some(&mut inner)` on the absent-key (fresh empty
20403    /// Mapping) and present-Mapping arms; `None` iff `key` holds a
20404    /// different [`serde_yaml::Value`] variant — a structural
20405    /// container-type mismatch the caller surfaces as its own
20406    /// domain-specific error (`Error::MissingField("spec.values must
20407    /// be a mapping")` for the caixa-flux Flux-HelmRelease overlay
20408    /// walker).
20409    ///
20410    /// The canonical shape 1 production call site in `caixa-flux`
20411    /// (`upsert_into_helmrelease_programs`'s per-`HelmRelease.spec.values`
20412    /// container-upsert on the way down to
20413    /// `spec.values.programs[]`) previously carried inline as a
20414    /// four-line block combining [`Self::entry_str_key`]'s entry-API
20415    /// key promotion (68d035e), an
20416    /// `.or_insert(Value::Mapping(Mapping::new()))` empty-Mapping
20417    /// default, and a `let Value::Mapping(inner) = _ else { Err(...) }`
20418    /// destructure — a two-token semantic payload (the schema key +
20419    /// the domain-specific type-mismatch diagnostic) buried under
20420    /// three boilerplate axes (`Value::Mapping(_)` variant promotion,
20421    /// `Mapping::new()` empty-container construction, the outer
20422    /// `let else` destructure). Peer to
20423    /// [`Self::entry_or_default_sequence`] on the sibling `Vec<Value>`-
20424    /// valued idempotent-container-upsert axis — the two together
20425    /// partition the entry-API-container-upsert surface exactly on the
20426    /// container-variant axis: [`Self::entry_or_default_mapping`] for
20427    /// nested-Mapping sub-blocks, [`Self::entry_or_default_sequence`]
20428    /// for list-shape sub-blocks.
20429    ///
20430    /// Sites lifted:
20431    ///
20432    ///   * caixa-flux's `upsert_into_helmrelease_programs` per-
20433    ///     `HelmRelease.spec.values` container-upsert
20434    ///     (`FLUX_KEY_VALUES` around the default fresh
20435    ///     `Value::Mapping`, on the way down to the nested
20436    ///     `spec.values.programs[]` sequence).
20437    ///
20438    /// Lifting collapses the four-line block into one method call the
20439    /// caller reads as intent (`mapping.entry_or_default_mapping(<KEY>)
20440    /// .ok_or(<ERR>)?` — "give me the nested Mapping at this schema
20441    /// key, defaulting empty if absent, else surface my domain
20442    /// error") rather than five hand-spelled positional artifacts
20443    /// (`serde_yaml::` path re-quote, `Value::Mapping(_)` promotion,
20444    /// `Mapping::new()` construction, the entry-API `.or_insert(...)`
20445    /// call, plus the outer `let Value::Mapping(_) = _ else {}`
20446    /// destructure). The next renderer to land — the per-`:politicas`
20447    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-cluster
20448    /// upsert walks
20449    /// `HelmRelease.spec.values.<library>.<:politicas-axis>`,
20450    /// idempotent-upserting nested-Mapping sub-blocks under each
20451    /// axis, MESH-COMPOSITION §III.2 #3), the `app-operator`'s typed
20452    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (which
20453    /// upserts `status.<axis>` nested-Mapping sub-blocks on partial
20454    /// reconciles, §III.2 #5), the M4 cross-cluster fan-out's
20455    /// per-cluster idempotent `HelmRelease.spec.values.<library>`
20456    /// container-upsert — gets the canonical entry-API-with-
20457    /// container-type-check for free with one method call, instead
20458    /// of re-inlining the four-line block.
20459    ///
20460    /// The default-empty-Mapping construction fires only on the
20461    /// absent-key arm (`.or_insert_with(...)` gates the closure on
20462    /// vacancy) — the present-key arm reuses the existing Mapping
20463    /// verbatim, so the caller's downstream writes on `&mut inner`
20464    /// compose with any prior overlay writes from earlier passes
20465    /// (the exact idempotent-upsert semantic the caixa-flux
20466    /// per-cluster `feira app deploy` write path depends on to
20467    /// preserve operator-pinned overlays across re-renders).
20468    fn entry_or_default_mapping(&mut self, key: &str) -> Option<&mut serde_yaml::Mapping>;
20469
20470    /// Fetch a `&mut Vec<serde_yaml::Value>` at `key`, defaulting an
20471    /// empty [`Vec<serde_yaml::Value>`] into place when the entry is
20472    /// absent. Returns `Some(&mut inner)` on the absent-key (fresh
20473    /// empty Sequence) and present-Sequence arms; `None` iff `key`
20474    /// holds a different [`serde_yaml::Value`] variant — a structural
20475    /// container-type mismatch the caller surfaces as its own
20476    /// domain-specific error (`Error::MissingField("programs must be
20477    /// a sequence")` for the caixa-flux fleet-programs upsert
20478    /// walkers).
20479    ///
20480    /// The canonical shape 2 production call sites in `caixa-flux`
20481    /// (`upsert_into_helmrelease_programs`'s per-
20482    /// `HelmRelease.spec.values.programs` container-upsert and
20483    /// `upsert_into_programs_yaml`'s top-level `programs:` container-
20484    /// upsert) previously carried inline as a four-line block
20485    /// combining [`Self::entry_str_key`]'s entry-API key promotion
20486    /// (68d035e), an `.or_insert(Value::Sequence(Vec::new()))`
20487    /// empty-Sequence default, and a `match _ { Value::Sequence(seq)
20488    /// => seq, _ => return Err(...) }` destructure — a two-token
20489    /// semantic payload (the schema key + the domain-specific
20490    /// type-mismatch diagnostic) buried under three boilerplate axes
20491    /// (`Value::Sequence(_)` variant promotion, `Vec::new()`
20492    /// empty-container construction, the outer `match` destructure).
20493    /// Peer to [`Self::entry_or_default_mapping`] on the sibling
20494    /// nested-Mapping-valued idempotent-container-upsert axis.
20495    ///
20496    /// Sites lifted:
20497    ///
20498    ///   * caixa-flux's `upsert_into_helmrelease_programs` per-
20499    ///     `HelmRelease.spec.values.programs` list-container-upsert
20500    ///     (`FLEET_PROGRAMS_KEY_PROGRAMS` around the default fresh
20501    ///     `Value::Sequence`, one path deep in a `HelmRelease`
20502    ///     `spec.values.` sub-tree);
20503    ///   * caixa-flux's `upsert_into_programs_yaml` per-top-level
20504    ///     `programs:` list-container-upsert
20505    ///     (`FLEET_PROGRAMS_KEY_PROGRAMS` around the default fresh
20506    ///     `Value::Sequence` — the sibling of the
20507    ///     `upsert_into_helmrelease_programs` site on the same key,
20508    ///     one path at the values.yaml root).
20509    ///
20510    /// Lifting collapses the four-line block into one method call the
20511    /// caller reads as intent (`mapping.entry_or_default_sequence(<KEY>)
20512    /// .ok_or(<ERR>)?` — "give me the list at this schema key,
20513    /// defaulting empty if absent, else surface my domain error")
20514    /// rather than five hand-spelled positional artifacts
20515    /// (`serde_yaml::` path re-quote, `Value::Sequence(_)` promotion,
20516    /// `Vec::new()` construction, the entry-API `.or_insert(...)`
20517    /// call, plus the outer `match { Value::Sequence(_) => _, _ =>
20518    /// return Err(_) }` destructure). The next renderer to land — the
20519    /// per-`:politicas` `CiliumClusterwideEnvoyConfig` emitter
20520    /// (whose per-cluster upsert walks nested list-shape sub-blocks
20521    /// `spec.resources[]` / `spec.listeners[]` / `spec.virtualHosts[]`
20522    /// under existing operator-pinned overlay CRs, MESH-COMPOSITION
20523    /// §III.2 #3), the `app-operator`'s typed
20524    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (which
20525    /// upserts `status.selectors[]` / `status.gates[]` list-shape
20526    /// sub-blocks on partial reconciles, §III.2 #5), the M4 cross-
20527    /// cluster fan-out's per-cluster idempotent
20528    /// `HelmRelease.spec.values.programs` list-upsert — gets the
20529    /// canonical entry-API-with-container-type-check for free with
20530    /// one method call, instead of re-inlining the four-line block.
20531    ///
20532    /// The default-empty-Sequence construction fires only on the
20533    /// absent-key arm (`.or_insert_with(...)` gates the closure on
20534    /// vacancy) — the present-key arm reuses the existing Vec
20535    /// verbatim, so the caller's downstream `upsert_named_entry`
20536    /// (10bf310) call on `&mut inner` composes with any prior
20537    /// entries the emitter wrote on earlier passes (the exact
20538    /// idempotent-upsert semantic the `feira app deploy` per-cluster
20539    /// write path depends on to preserve prior `programs[]` entries
20540    /// across per-Servico rewrites).
20541    fn entry_or_default_sequence(&mut self, key: &str) -> Option<&mut Vec<serde_yaml::Value>>;
20542}
20543
20544impl MappingExt for serde_yaml::Mapping {
20545    #[inline]
20546    fn insert_str_key(&mut self, key: &str, value: serde_yaml::Value) -> Option<serde_yaml::Value> {
20547        self.insert(serde_yaml::Value::String(key.to_string()), value)
20548    }
20549
20550    #[inline]
20551    fn insert_string<V: Into<String>>(&mut self, key: &str, value: V) -> Option<serde_yaml::Value> {
20552        self.insert_str_key(key, serde_yaml::Value::String(value.into()))
20553    }
20554
20555    #[inline]
20556    fn insert_number<N: Into<serde_yaml::Number>>(
20557        &mut self,
20558        key: &str,
20559        value: N,
20560    ) -> Option<serde_yaml::Value> {
20561        self.insert_str_key(key, serde_yaml::Value::Number(value.into()))
20562    }
20563
20564    #[inline]
20565    fn insert_mapping(
20566        &mut self,
20567        key: &str,
20568        value: serde_yaml::Mapping,
20569    ) -> Option<serde_yaml::Value> {
20570        self.insert_str_key(key, serde_yaml::Value::Mapping(value))
20571    }
20572
20573    #[inline]
20574    fn insert_sequence(
20575        &mut self,
20576        key: &str,
20577        value: Vec<serde_yaml::Value>,
20578    ) -> Option<serde_yaml::Value> {
20579        self.insert_str_key(key, serde_yaml::Value::Sequence(value))
20580    }
20581
20582    #[inline]
20583    fn insert_singleton_mapping_sequence(
20584        &mut self,
20585        key: &str,
20586        value: serde_yaml::Mapping,
20587    ) -> Option<serde_yaml::Value> {
20588        self.insert_str_key(key, singleton_mapping_sequence(value))
20589    }
20590
20591    #[inline]
20592    fn entry_str_key(&mut self, key: &str) -> serde_yaml::mapping::Entry<'_> {
20593        self.entry(serde_yaml::Value::String(key.to_string()))
20594    }
20595
20596    #[inline]
20597    fn insert_str_key_if_some(
20598        &mut self,
20599        key: &str,
20600        value: Option<&serde_yaml::Value>,
20601    ) -> Option<serde_yaml::Value> {
20602        value.and_then(|v| self.insert_str_key(key, v.clone()))
20603    }
20604
20605    #[inline]
20606    fn entry_or_default_mapping(&mut self, key: &str) -> Option<&mut serde_yaml::Mapping> {
20607        match self
20608            .entry_str_key(key)
20609            .or_insert_with(|| serde_yaml::Value::Mapping(serde_yaml::Mapping::new()))
20610        {
20611            serde_yaml::Value::Mapping(m) => Some(m),
20612            _ => None,
20613        }
20614    }
20615
20616    #[inline]
20617    fn entry_or_default_sequence(&mut self, key: &str) -> Option<&mut Vec<serde_yaml::Value>> {
20618        match self
20619            .entry_str_key(key)
20620            .or_insert_with(|| serde_yaml::Value::Sequence(Vec::new()))
20621        {
20622            serde_yaml::Value::Sequence(s) => Some(s),
20623            _ => None,
20624        }
20625    }
20626}
20627
20628/// Extension methods for the [`Vec<serde_yaml::Value>`] emission
20629/// surface that the K8s-artifact-emit sites of `caixa-mesh` /
20630/// `caixa-flux` / `caixa-helm` / `caixa-core::render` build up as
20631/// `spec.ingress[]` / `spec.rules[]` / `spec.hostnames[]` / per-
20632/// programs.yaml-entry payloads before wrapping each vec as a
20633/// [`serde_yaml::Value::Sequence`] on an outer [`serde_yaml::Mapping`]
20634/// (via [`MappingExt::insert_sequence`]).
20635///
20636/// Peer to [`MappingExt`] on the sibling [`serde_yaml::Value`]-
20637/// construction surface: [`MappingExt`] closes the per-key-and-value
20638/// insert primitive every schema-key axis reaches through;
20639/// [`SequenceExt`] closes the per-list-element push primitive every
20640/// per-iteration append site reaches through when the built-up
20641/// [`serde_yaml::Value`] variant is uniform across a loop body (e.g.
20642/// every element is a fresh [`serde_yaml::Value::Mapping`], not a
20643/// heterogeneous mix of `Mapping` / `String` / `Sequence`).
20644///
20645/// Each method mints the same `Value::<Variant>(<payload>)` promotion
20646/// the caller would otherwise re-inline as
20647/// `vec.push(serde_yaml::Value::<Variant>(<payload>))` on every
20648/// iteration. Same variant-promotion contract as [`MappingExt`]'s
20649/// typed inserts, applied to the sequence-append axis instead of the
20650/// mapping-insert axis — so a future rebrand of the `Value` variant
20651/// wrapping (e.g. to a Server-Side-Apply-typed
20652/// [`serde_yaml::Value::Tagged`] per-list-element ownership axis)
20653/// reaches both `Mapping`-insert and `Vec<Value>`-push sites through
20654/// one lift.
20655pub trait SequenceExt {
20656    /// Append `Value::Mapping(value)` to `self` — the per-iteration
20657    /// append shape that combines a `Vec<serde_yaml::Value>::push`
20658    /// with an automatic [`serde_yaml::Value::Mapping`] promotion of a
20659    /// pre-built [`serde_yaml::Mapping`] element.
20660    ///
20661    /// The canonical shape 4 production call sites across `caixa-mesh`
20662    /// previously carried inline as the three-token block
20663    /// `<vec>.push(serde_yaml::Value::Mapping(<M>))` — a one-token
20664    /// semantic payload (the per-iteration `Mapping`) buried under a
20665    /// two-axis boilerplate (`serde_yaml::` path re-quote,
20666    /// `Value::Mapping(_)` promotion) around a `Mapping` variable the
20667    /// caller already built.
20668    ///
20669    /// Sites lifted:
20670    ///
20671    ///   * caixa-mesh's `programs_for_aplicacao` per-`:membros`
20672    ///     programs.yaml entry append (per-member entry `Mapping` →
20673    ///     the fan-out `Vec<Value>`);
20674    ///   * caixa-mesh's `cilium_network_policies` per-edge
20675    ///     `spec.ingress[].toPorts[]` L4-and-L7 port-and-rule append
20676    ///     (per-`(:de, :para)` group's per-edge `to_port` Mapping →
20677    ///     the `to_ports_seq` Vec);
20678    ///   * caixa-mesh's `cilium_network_policies` per-policy
20679    ///     top-level CNP-document append (per-`(:de, :para)` group's
20680    ///     built `policy` Mapping → the render-output `Vec<Value>`);
20681    ///   * caixa-mesh's `gateway_routes` per-HTTPRoute-rule
20682    ///     `spec.rules[]` append (per-path built `rule` Mapping → the
20683    ///     `rules` Vec).
20684    ///
20685    /// Lifting collapses the three-token block into one method call
20686    /// the caller reads as intent (`<vec>.push_mapping(<M>)` —
20687    /// "append this built inner `M` as the next `Value::Mapping`
20688    /// element") rather than three hand-spelled positional artifacts
20689    /// (`serde_yaml::` path re-quote, `Value::Mapping(_)` promotion,
20690    /// plus the `.push(_)` call itself). Peer to
20691    /// [`MappingExt::insert_singleton_mapping_sequence`] on the
20692    /// singleton-Mapping-list-shape axis: [`Self::push_mapping`]
20693    /// builds up a multi-element `Vec<Value>` per iteration when the
20694    /// caller then calls [`MappingExt::insert_sequence`] to route the
20695    /// finished vec under a schema key;
20696    /// [`MappingExt::insert_singleton_mapping_sequence`] fuses the
20697    /// singleton wrap + the schema-key insert into one call when the
20698    /// caller has exactly one Mapping element to emit under a schema
20699    /// key.
20700    ///
20701    /// The next renderer to land — the per-`:politicas`
20702    /// `CiliumClusterwideEnvoyConfig` emitter (whose per-policy
20703    /// `spec.resources[]` / `spec.listeners[]` / `spec.virtualHosts[]`
20704    /// list-shape axes fan out multi-Mapping-element per iteration,
20705    /// MESH-COMPOSITION §III.2 #3), the `app-operator`'s typed
20706    /// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer (per-
20707    /// `spec.selectors[]` / per-`spec.gates[]` multi-element append,
20708    /// §III.2 #5), the M4 cross-cluster fan-out's per-cluster
20709    /// multi-entry `Service.spec.ports[]` /
20710    /// `HTTPRoute.spec.rules[].backendRefs[]` list append, the future
20711    /// `caixa-otel` OpenTelemetry-Collector per-pipeline
20712    /// `receivers[]` / `processors[]` / `exporters[]` multi-element
20713    /// append — gets the canonical `Value::Mapping`-promoted append
20714    /// for free with one method call, instead of re-inlining the
20715    /// three-token `Value::Mapping(_)` promotion.
20716    fn push_mapping(&mut self, value: serde_yaml::Mapping);
20717}
20718
20719impl SequenceExt for Vec<serde_yaml::Value> {
20720    #[inline]
20721    fn push_mapping(&mut self, value: serde_yaml::Mapping) {
20722        self.push(serde_yaml::Value::Mapping(value));
20723    }
20724}
20725
20726#[cfg(test)]
20727mod tests {
20728    use super::*;
20729    use crate::{BehaviorSpec, CaixaKind, LimitsSpec, UpgradeFromEntry, UpgradeInstruction};
20730    use std::path::PathBuf;
20731    use std::time::Duration;
20732
20733    fn bare_servico() -> Caixa {
20734        Caixa {
20735            nome: "hello-rio".into(),
20736            versao: "0.1.0".into(),
20737            kind: CaixaKind::Servico,
20738            edicao: Some("2026".into()),
20739            descricao: None,
20740            repositorio: None,
20741            licenca: None,
20742            autores: vec![],
20743            etiquetas: vec![],
20744            deps: vec![],
20745            deps_dev: vec![],
20746            exe: vec![],
20747            bibliotecas: vec![],
20748            servicos: vec!["servicos/hello-rio.computeunit.yaml".into()],
20749            limits: None,
20750            behavior: None,
20751            upgrade_from: vec![],
20752            estrategia: None,
20753            max_restarts: None,
20754            restart_window: None,
20755            children: vec![],
20756            membros: vec![],
20757            contratos: vec![],
20758            politicas: None,
20759            placement: None,
20760            entrada: None,
20761            ci: None,
20762        }
20763    }
20764
20765    #[test]
20766    fn empty_caixa_returns_empty_overlay() {
20767        let overlay = servico_m2_overlay(&bare_servico()).unwrap();
20768        assert!(
20769            overlay.is_empty(),
20770            "a Caixa with no M2 slots emits zero overlay fragments"
20771        );
20772    }
20773
20774    #[test]
20775    fn empty_typed_specs_are_skipped_like_unset_ones() {
20776        // `Some(LimitsSpec::default())` (every axis None) and
20777        // `Some(BehaviorSpec::default())` (every callback None) must
20778        // round-trip identical to `None` — the is_empty()-skip
20779        // invariant the renderers' "empty M2 slots do not appear"
20780        // tests pinned inline before this lift.
20781        let mut c = bare_servico();
20782        c.limits = Some(LimitsSpec::default());
20783        c.behavior = Some(BehaviorSpec::default());
20784        let overlay = servico_m2_overlay(&c).unwrap();
20785        assert!(overlay.is_empty());
20786    }
20787
20788    #[test]
20789    fn limits_slot_appears_under_camelcase_key() {
20790        let mut c = bare_servico();
20791        c.limits = Some(LimitsSpec {
20792            memory: Some(64 * 1024 * 1024),
20793            fuel: Some(1_000_000),
20794            wall_clock: Some(Duration::from_secs(30)),
20795            cpu: Some(500),
20796        });
20797        let overlay = servico_m2_overlay(&c).unwrap();
20798        assert_eq!(overlay.len(), 1);
20799        let limits = overlay.get(M2_KEY_LIMITS).expect("limits key present");
20800        assert_eq!(
20801            limits.get(M2_LIMITS_KEY_MEMORY).and_then(|m| m.as_str()),
20802            Some("64MiB")
20803        );
20804        assert_eq!(
20805            limits
20806                .get(M2_LIMITS_KEY_WALL_CLOCK)
20807                .and_then(|m| m.as_str()),
20808            Some("30s")
20809        );
20810    }
20811
20812    #[test]
20813    fn behavior_slot_appears_under_camelcase_key() {
20814        let mut c = bare_servico();
20815        c.behavior = Some(BehaviorSpec {
20816            on_init: Some(PathBuf::from("lib/init.lisp")),
20817            on_call: Some(PathBuf::from("lib/handlers.lisp")),
20818            ..Default::default()
20819        });
20820        let overlay = servico_m2_overlay(&c).unwrap();
20821        let behavior = overlay.get(M2_KEY_BEHAVIOR).expect("behavior key present");
20822        assert_eq!(
20823            behavior
20824                .get(M2_BEHAVIOR_KEY_ON_INIT)
20825                .and_then(|v| v.as_str()),
20826            Some("lib/init.lisp")
20827        );
20828        assert_eq!(
20829            behavior
20830                .get(M2_BEHAVIOR_KEY_ON_CALL)
20831                .and_then(|v| v.as_str()),
20832            Some("lib/handlers.lisp")
20833        );
20834    }
20835
20836    #[test]
20837    fn upgrade_from_slot_appears_under_camelcase_key() {
20838        let mut c = bare_servico();
20839        c.upgrade_from = vec![UpgradeFromEntry {
20840            from: "0.0.9".into(),
20841            instructions: vec![UpgradeInstruction::LoadModule {
20842                module: "hello-rio".into(),
20843            }],
20844        }];
20845        let overlay = servico_m2_overlay(&c).unwrap();
20846        let upgrade = overlay
20847            .get(M2_KEY_UPGRADE_FROM)
20848            .expect("upgradeFrom key present");
20849        let arr = upgrade.as_sequence().expect("sequence");
20850        assert_eq!(arr.len(), 1);
20851        assert_eq!(
20852            arr[0]
20853                .get(M2_UPGRADE_FROM_KEY_FROM)
20854                .and_then(|v| v.as_str()),
20855            Some("0.0.9")
20856        );
20857    }
20858
20859    #[test]
20860    fn all_three_slots_appear_in_alphabetical_iteration_order() {
20861        // BTreeMap iteration is sorted by key — pin that the renderers
20862        // can rely on a deterministic iteration order, which feeds
20863        // into deterministic YAML output (the value-as-proof property
20864        // THEORY.md §V.2.7 "render determinism" requires).
20865        let mut c = bare_servico();
20866        c.limits = Some(LimitsSpec {
20867            memory: Some(64 * 1024 * 1024),
20868            ..Default::default()
20869        });
20870        c.behavior = Some(BehaviorSpec {
20871            on_init: Some(PathBuf::from("lib/init.lisp")),
20872            ..Default::default()
20873        });
20874        c.upgrade_from = vec![UpgradeFromEntry {
20875            from: "0.0.9".into(),
20876            instructions: vec![UpgradeInstruction::LoadModule {
20877                module: "hello-rio".into(),
20878            }],
20879        }];
20880        let overlay = servico_m2_overlay(&c).unwrap();
20881        let keys: Vec<_> = overlay.keys().copied().collect();
20882        assert_eq!(
20883            keys,
20884            vec![M2_KEY_BEHAVIOR, M2_KEY_LIMITS, M2_KEY_UPGRADE_FROM]
20885        );
20886    }
20887
20888    // ── servico_spec_and_m2_overlay_entries — composed splice ────────────
20889    //
20890    // The compound peer of `servico_m2_overlay` on the ComputeUnit-YAML
20891    // `spec.*` + M2-overlay axis: fuses the two prior inline for-loops
20892    // caixa-flux::programs_yaml_entry and caixa-helm::build_values_yaml
20893    // both carried around `string_keyed_entries` + `servico_m2_overlay`
20894    // into one canonical composition. The pins below bracket the shape
20895    // end-to-end (spec.* keys first + preserved-insertion-order, then M2
20896    // slots in BTreeMap-key order at every M2 key not already claimed by
20897    // spec.*).
20898
20899    fn cu_yaml_with_spec_fields(spec_yaml: &str) -> serde_yaml::Value {
20900        serde_yaml::from_str(&format!(
20901            "apiVersion: wasm.pleme.io/v1alpha1\nkind: ComputeUnit\nmetadata:\n  name: hello-rio\nspec:\n{spec_yaml}"
20902        ))
20903        .unwrap()
20904    }
20905
20906    #[test]
20907    fn servico_spec_and_m2_overlay_entries_empty_caixa_and_empty_spec_yields_empty() {
20908        let cu = cu_yaml_with_spec_fields("  {}\n");
20909        let spec = cu.get(KUBE_KEY_SPEC).unwrap();
20910        let out = servico_spec_and_m2_overlay_entries(&bare_servico(), spec).unwrap();
20911        assert!(
20912            out.is_empty(),
20913            "empty spec + empty M2 surface yields zero entries \
20914             (both loops short-circuit vacuously)"
20915        );
20916    }
20917
20918    #[test]
20919    fn servico_spec_and_m2_overlay_entries_splices_spec_fields_in_source_insertion_order() {
20920        // The spec.* field-splice loop preserves the source YAML
20921        // Mapping's insertion order — caixa-flux's `serde_yaml::Mapping`
20922        // target reads this back verbatim, so a rebrand of the source
20923        // ComputeUnit YAML's field ordering must not silently reorder
20924        // the emitted programs.yaml entry.
20925        let cu = cu_yaml_with_spec_fields(
20926            "  module:\n    source: oci://ghcr.io/pleme-io/hello-rio:v0.1.0\n  \
20927             trigger:\n    service: {port: 8080}\n  capabilities:\n    - env\n",
20928        );
20929        let spec = cu.get(KUBE_KEY_SPEC).unwrap();
20930        let out = servico_spec_and_m2_overlay_entries(&bare_servico(), spec).unwrap();
20931        let keys: Vec<&str> = out.iter().map(|(k, _)| k.as_str()).collect();
20932        assert_eq!(
20933            keys,
20934            vec![
20935                COMPUTEUNIT_SPEC_KEY_MODULE,
20936                COMPUTEUNIT_SPEC_KEY_TRIGGER,
20937                COMPUTEUNIT_SPEC_KEY_CAPABILITIES,
20938            ],
20939            "spec.* keys must appear in source-Mapping insertion order",
20940        );
20941    }
20942
20943    #[test]
20944    fn servico_spec_and_m2_overlay_entries_appends_m2_slots_after_spec_in_canonical_key_order() {
20945        // Bracket the second-half of the composition — the M2 overlay
20946        // walk lands after the spec.* splice, in BTreeMap-key ordering
20947        // (behavior → limits → upgradeFrom).
20948        let cu = cu_yaml_with_spec_fields(
20949            "  module:\n    source: oci://ghcr.io/pleme-io/hello-rio:v0.1.0\n",
20950        );
20951        let spec = cu.get(KUBE_KEY_SPEC).unwrap();
20952        let mut c = bare_servico();
20953        c.limits = Some(LimitsSpec {
20954            memory: Some(64 * 1024 * 1024),
20955            ..Default::default()
20956        });
20957        c.behavior = Some(BehaviorSpec {
20958            on_init: Some(PathBuf::from("lib/init.lisp")),
20959            ..Default::default()
20960        });
20961        c.upgrade_from = vec![UpgradeFromEntry {
20962            from: "0.0.9".into(),
20963            instructions: vec![UpgradeInstruction::LoadModule {
20964                module: "hello-rio".into(),
20965            }],
20966        }];
20967        let out = servico_spec_and_m2_overlay_entries(&c, spec).unwrap();
20968        let keys: Vec<&str> = out.iter().map(|(k, _)| k.as_str()).collect();
20969        assert_eq!(
20970            keys,
20971            vec![
20972                COMPUTEUNIT_SPEC_KEY_MODULE,
20973                M2_KEY_BEHAVIOR,
20974                M2_KEY_LIMITS,
20975                M2_KEY_UPGRADE_FROM,
20976            ],
20977            "M2 slots must land after the spec.* splice, in canonical \
20978             BTreeMap key order",
20979        );
20980    }
20981
20982    #[test]
20983    fn servico_spec_and_m2_overlay_entries_or_insert_precedence_spec_wins_on_collision() {
20984        // The or_insert precedence rule the two prior inline blocks
20985        // shared: when the ComputeUnit YAML's `spec.*` sub-mapping
20986        // already carries the M2 slot's key (an author-authored
20987        // ComputeUnit `spec.limits` overriding the manifest-derived
20988        // `caixa.limits` overlay), the spec.* value stays and the M2
20989        // overlay's value is skipped. Regression-guards against a
20990        // future reversal ("M2 wins on collision") silently changing
20991        // the composition without an explicit slot-precedence flip at
20992        // the helper.
20993        let cu = cu_yaml_with_spec_fields(
20994            "  limits:\n    memory: from-spec\n  module:\n    source: oci://x\n",
20995        );
20996        let spec = cu.get(KUBE_KEY_SPEC).unwrap();
20997        let mut c = bare_servico();
20998        c.limits = Some(LimitsSpec {
20999            memory: Some(64 * 1024 * 1024),
21000            ..Default::default()
21001        });
21002        let out = servico_spec_and_m2_overlay_entries(&c, spec).unwrap();
21003        let limits_entries: Vec<&(String, serde_yaml::Value)> =
21004            out.iter().filter(|(k, _)| k == M2_KEY_LIMITS).collect();
21005        assert_eq!(
21006            limits_entries.len(),
21007            1,
21008            "on collision the M2 overlay's `limits` entry must be \
21009             filtered out — spec.* wins, and appears exactly once",
21010        );
21011        assert_eq!(
21012            limits_entries[0]
21013                .1
21014                .get(M2_LIMITS_KEY_MEMORY)
21015                .and_then(|v| v.as_str()),
21016            Some("from-spec"),
21017            "the surviving `limits` entry must carry the spec.* value, \
21018             not the manifest-derived M2 overlay's value",
21019        );
21020    }
21021
21022    #[test]
21023    fn servico_spec_and_m2_overlay_entries_short_circuits_on_non_mapping_spec() {
21024        // Sibling `string_keyed_entries` docstring pins the
21025        // non-Mapping short-circuit; extend it to the composed splice
21026        // — a spec that isn't a Mapping yields zero spec.* entries,
21027        // and only the M2 overlay contributes. Bracket-guard against a
21028        // future refactor that swaps `string_keyed_entries` for a
21029        // stricter parser silently dropping the M2 half too.
21030        let non_mapping_spec = serde_yaml::Value::String("not-a-mapping".into());
21031        let mut c = bare_servico();
21032        c.limits = Some(LimitsSpec {
21033            memory: Some(64 * 1024 * 1024),
21034            ..Default::default()
21035        });
21036        let out = servico_spec_and_m2_overlay_entries(&c, &non_mapping_spec).unwrap();
21037        let keys: Vec<&str> = out.iter().map(|(k, _)| k.as_str()).collect();
21038        assert_eq!(
21039            keys,
21040            vec![M2_KEY_LIMITS],
21041            "non-Mapping spec short-circuits the spec.* splice; the M2 \
21042             overlay still contributes its filled slots",
21043        );
21044    }
21045
21046    #[test]
21047    fn servico_spec_and_m2_overlay_entries_matches_hand_written_composition() {
21048        // Cross-check the lifted composition against the hand-written
21049        // two-loop shape the two prior inline blocks carried. A drift
21050        // between the helper and the inline composition would silently
21051        // emit a different key set / ordering / precedence at every
21052        // routed renderer — pin the equivalence so the helper stays a
21053        // drop-in replacement for both.
21054        let cu = cu_yaml_with_spec_fields(
21055            "  module:\n    source: oci://ghcr.io/pleme-io/hello-rio:v0.1.0\n  \
21056             trigger:\n    service: {port: 8080}\n",
21057        );
21058        let spec = cu.get(KUBE_KEY_SPEC).unwrap();
21059        let mut c = bare_servico();
21060        c.limits = Some(LimitsSpec {
21061            memory: Some(32 * 1024 * 1024),
21062            ..Default::default()
21063        });
21064        c.behavior = Some(BehaviorSpec {
21065            on_call: Some(PathBuf::from("lib/handlers.lisp")),
21066            ..Default::default()
21067        });
21068
21069        let via_helper = servico_spec_and_m2_overlay_entries(&c, spec).unwrap();
21070
21071        let mut via_inline: Vec<(String, serde_yaml::Value)> = Vec::new();
21072        let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();
21073        for (k, v) in string_keyed_entries(spec) {
21074            seen.insert(k.to_string());
21075            via_inline.push((k.to_string(), v.clone()));
21076        }
21077        for (key, value) in servico_m2_overlay(&c).unwrap() {
21078            if !seen.contains(key) {
21079                via_inline.push((key.to_string(), value));
21080            }
21081        }
21082
21083        assert_eq!(
21084            via_helper, via_inline,
21085            "servico_spec_and_m2_overlay_entries must byte-equal the \
21086             hand-written two-loop composition (spec.* splice + M2 \
21087             overlay with or_insert precedence) the two prior inline \
21088             call sites carried",
21089        );
21090    }
21091
21092    #[test]
21093    fn pleme_label_consts_share_canonical_prefix() {
21094        // Single-source-of-truth invariant: every pleme-io label key
21095        // is `<PLEME_LABEL_PREFIX>/<axis>`. A future label-namespace
21096        // rebrand is a one-line PLEME_LABEL_PREFIX edit + this test
21097        // pins the contract that no other label leaks past the lift.
21098        for k in [LABEL_APLICACAO, LABEL_PROGRAM, LABEL_CONTRATO] {
21099            assert!(
21100                k.starts_with(PLEME_LABEL_PREFIX),
21101                "label key {k:?} must share the {PLEME_LABEL_PREFIX:?} prefix"
21102            );
21103            // Each label is `<prefix>/<axis>` — the suffix is non-empty
21104            // (the `/` separator is followed by the axis name).
21105            let suffix = k.strip_prefix(PLEME_LABEL_PREFIX).unwrap();
21106            assert!(suffix.starts_with('/'));
21107            assert!(suffix.len() > 1, "axis name must be non-empty for {k:?}");
21108        }
21109    }
21110
21111    #[test]
21112    fn pleme_label_consts_have_expected_canonical_values() {
21113        // Pin the actual string values so a typo in the lift can't
21114        // silently rebrand the whole pleme-io label namespace. These
21115        // strings are part of the cluster-side contract with the
21116        // lareira-fleet-programs chart + Cilium identity layer + Hubble
21117        // flow attribution; changing any of them is a coordinated
21118        // multi-repo migration, not an incidental edit.
21119        assert_eq!(PLEME_LABEL_PREFIX, "pleme.pleme.io");
21120        assert_eq!(LABEL_APLICACAO, "pleme.pleme.io/aplicacao");
21121        assert_eq!(LABEL_PROGRAM, "pleme.pleme.io/program");
21122        assert_eq!(LABEL_CONTRATO, "pleme.pleme.io/contrato");
21123    }
21124
21125    #[test]
21126    fn default_namespace_pins_canonical_value() {
21127        // Pin the actual string so a typo in this lift can't silently
21128        // rebrand the cluster-side namespace every renderer emits
21129        // into. The string is part of the cluster-side contract with
21130        // the lareira-fleet-programs aggregator chart, the per-cluster
21131        // CiliumNetworkPolicy `endpointSelector` namespace scope, the
21132        // Gateway / HTTPRoute apply namespace, and the future M4
21133        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's apply
21134        // namespace; changing it is a coordinated multi-repo migration
21135        // (the per-cluster k8s repo's namespaces, every
21136        // lareira-fleet-programs HelmRelease's targetNamespace, every
21137        // ComputeUnit's `metadata.namespace`), not an incidental edit.
21138        // Peer to `pleme_label_consts_have_expected_canonical_values`
21139        // on the canonical-string-value-pin axis for the
21140        // `PLEME_LABEL_PREFIX` / `LABEL_*` constants.
21141        assert_eq!(DEFAULT_NAMESPACE, "tatara-system");
21142    }
21143
21144    #[test]
21145    fn default_flux_system_namespace_pins_canonical_value() {
21146        // Pin the actual string so a typo in this lift can't silently
21147        // rebrand the FluxCD installation namespace the rendered
21148        // `kustomization.yaml`'s `metadata.namespace` /
21149        // `spec.sourceRef.name` axes consume. The string is part of the
21150        // cluster-side contract with the `flux bootstrap` pipeline (the
21151        // bootstrap convention names the `GitRepository` after the
21152        // installation namespace, so both axes are the same load-bearing
21153        // string), the `kustomize-controller` watch-window scope (a
21154        // drifted value sits outside the controller's watch window and
21155        // is never reconciled), and the per-cluster k8s repo's flux
21156        // bootstrap manifests; changing it is a coordinated multi-repo
21157        // migration, not an incidental edit. Peer to
21158        // `default_namespace_pins_canonical_value` on the
21159        // canonical-string-value-pin axis for the workload-side
21160        // [`DEFAULT_NAMESPACE`] constant.
21161        assert_eq!(DEFAULT_FLUX_SYSTEM_NAMESPACE, "flux-system");
21162    }
21163
21164    #[test]
21165    fn default_flux_system_namespace_is_a_valid_dns_1123_label() {
21166        // Cross-axis invariant: the FluxCD installation namespace lands
21167        // as `metadata.namespace` on every emitted `Kustomization`
21168        // resource and as `spec.sourceRef.name` (a K8s resource name
21169        // under the same DNS-1123 floor), and the K8s apiserver
21170        // enforces the DNS-1123 label rule on both. Pinning this here
21171        // means a future rebrand on the canonical lift can't silently
21172        // land a value the apiserver refuses at the *first*
21173        // `kustomization.yaml` apply against a cluster, far from the
21174        // rebrand commit's source — the typed [`is_dns_1123_label`]
21175        // floor rejects it at caixa-core build time on the canonical
21176        // lift, before any renderer consumes the value. Same shape as
21177        // `default_namespace_is_a_valid_dns_1123_label` on the
21178        // workload-side [`DEFAULT_NAMESPACE`] axis.
21179        assert!(
21180            is_dns_1123_label(DEFAULT_FLUX_SYSTEM_NAMESPACE).is_ok(),
21181            "DEFAULT_FLUX_SYSTEM_NAMESPACE {DEFAULT_FLUX_SYSTEM_NAMESPACE:?} must be a valid \
21182             DNS-1123 label — every K8s apiserver-side schema enforces \
21183             this rule on `metadata.namespace`"
21184        );
21185    }
21186
21187    #[test]
21188    fn default_flux_reconcile_interval_pins_canonical_value() {
21189        // Pin the actual string so a typo in this lift can't silently
21190        // rebrand the substrate-side default Flux v2 reconcile-poll
21191        // cadence duration scalar the substrate's per-caixa
21192        // `cluster_bundle` renderer seeds into every emitted per-caixa
21193        // Flux v2 CR (GitRepository / HelmRelease / Kustomization) at
21194        // its `spec.interval` axis when the operator doesn't pin a per-
21195        // caixa override. The string is part of the cluster-side
21196        // contract with the Flux v2 source-controller / helm-controller
21197        // / kustomize-controller trio: each controller's per-CR admission
21198        // gate parses the value via `metav1.ParseDuration` before
21199        // installing the per-CR watch, and the resulting cadence pins
21200        // the per-CR reconcile-freshness / cluster-load tradeoff every
21201        // substrate-side Flux v2 pipeline runs at. Changing this value
21202        // is a coordinated substrate-side reconcile-cadence promotion
21203        // (a `10m` → `5m` migration once lower-latency-poll optimizations
21204        // ship, a `10m` → `15m` migration on cost-optimized clusters
21205        // where per-CR source-controller poll cost outweighs the
21206        // reconcile-freshness gain), not an incidental edit. Peer to
21207        // `default_namespace_pins_canonical_value` and
21208        // `default_gateway_class_name_pins_canonical_value` on the
21209        // canonical-substrate-default-load-bearing-scalar pin surface.
21210        assert_eq!(DEFAULT_FLUX_RECONCILE_INTERVAL, "10m");
21211    }
21212
21213    #[test]
21214    fn default_flux_reconcile_interval_is_a_valid_metav1_duration_scalar() {
21215        // Cross-axis grammar invariant: the Flux v2 controller-side per-
21216        // CR admission gate parses the reconcile-poll cadence scalar via
21217        // `metav1.ParseDuration` before installing the per-CR watch. The
21218        // Go-duration-format grammar is non-empty, ASCII, and structured
21219        // as `<digits><unit>[<digits><unit>...]` where each unit is one
21220        // of `{ns, us, µs, ms, s, m, h}`. Pin a floor that catches the
21221        // canonical drift footguns — an empty scalar (`""` — admission
21222        // gate rejects), a non-ASCII-alphanumeric byte (`"10 m"` — the
21223        // whitespace defeats the parser), a missing-unit scalar (`"10"`
21224        // — the parser rejects for lack of a unit suffix), or a leading-
21225        // non-digit scalar (`"m10"` — the parser rejects for lack of a
21226        // leading magnitude). A future rebrand on the canonical lift
21227        // that lands a value outside the Go-duration-format grammar
21228        // would surface here at caixa-core build time on the canonical
21229        // lift, before any renderer consumes the value. Same shape as
21230        // `default_namespace_is_a_valid_dns_1123_label` /
21231        // `default_flux_system_namespace_is_a_valid_dns_1123_label` /
21232        // `default_gateway_class_name_is_a_valid_dns_1123_label` on the
21233        // peer canonical-substrate-default-grammar-floor surface.
21234        let v = DEFAULT_FLUX_RECONCILE_INTERVAL;
21235        assert!(
21236            !v.is_empty(),
21237            "DEFAULT_FLUX_RECONCILE_INTERVAL {v:?} must be non-empty \
21238             per the Flux v2 controller-side `metav1.ParseDuration` \
21239             admission gate"
21240        );
21241        assert!(
21242            v.chars().all(|c| c.is_ascii_alphanumeric()),
21243            "DEFAULT_FLUX_RECONCILE_INTERVAL {v:?} must be ASCII-\
21244             alphanumeric throughout per the Go-duration-format grammar \
21245             — no whitespace / separator bytes the `metav1.ParseDuration` \
21246             admission gate would reject"
21247        );
21248        let first = v.chars().next().expect("non-empty");
21249        assert!(
21250            first.is_ascii_digit(),
21251            "DEFAULT_FLUX_RECONCILE_INTERVAL {v:?} first byte {first:?} \
21252             must be an ASCII digit per the Go-duration-format grammar \
21253             — the leading magnitude precedes the unit suffix; a leading \
21254             non-digit defeats `metav1.ParseDuration`"
21255        );
21256        let last = v.chars().next_back().expect("non-empty");
21257        assert!(
21258            last.is_ascii_alphabetic() && last.is_ascii_lowercase(),
21259            "DEFAULT_FLUX_RECONCILE_INTERVAL {v:?} last byte {last:?} \
21260             must be an ASCII lowercase alphabetic unit suffix per the \
21261             Go-duration-format grammar — the trailing unit follows the \
21262             magnitude; an unterminated magnitude defeats \
21263             `metav1.ParseDuration`"
21264        );
21265    }
21266
21267    #[test]
21268    fn default_flux_chart_source_subpath_pins_canonical_value() {
21269        // Pin the actual scalar so a typo in this lift can't silently
21270        // rebrand the substrate-side default Flux v2
21271        // `HelmRelease.spec.chart.spec.chart` chart-directory-in-
21272        // GitRepository-source sub-path the substrate's per-caixa
21273        // `cluster_bundle` renderer seeds into every emitted per-caixa
21274        // `helmrelease.yaml` document. The value is part of the
21275        // cluster-side contract with the Flux v2 helm-controller (the
21276        // per-CR chart-open loop uses this to locate the
21277        // `Chart.yaml` + `values.yaml` pair inside the paired
21278        // GitRepository clone root); changing it is a coordinated
21279        // substrate-side chart-directory-in-git-source promotion
21280        // (a `"chart"` → `"charts"` migration on a per-caixa multi-chart
21281        // layout landing, a `"chart"` → `"helm"` migration on a
21282        // cross-language convention alignment, a `"chart"` → `"deploy"`
21283        // migration on a per-caixa-deploy-directory naming migration),
21284        // not an incidental edit. Peer to
21285        // `default_flux_reconcile_interval_pins_canonical_value` +
21286        // `flux_helmrelease_remediation_retries_default_pins_canonical_value`
21287        // on the canonical-Flux-v2-per-CR-substrate-default-scalar pin
21288        // surface.
21289        assert_eq!(DEFAULT_FLUX_CHART_SOURCE_SUBPATH, "chart");
21290    }
21291
21292    #[test]
21293    fn default_flux_chart_source_subpath_is_a_valid_relative_directory_scalar() {
21294        // Cross-axis grammar invariant: the Flux v2 source-controller
21295        // resolves the per-CR `HelmRelease.spec.chart.spec.chart` scalar
21296        // as a directory path relative to the paired `GitRepository`
21297        // clone root. Pin a floor that catches the canonical drift
21298        // footguns — an empty scalar (`""` — the source-controller-side
21299        // per-CR chart-open loop rejects for lack of a target directory),
21300        // a leading-separator scalar (`"/chart"` — the source-controller
21301        // rejects for the absolute-path shape breaking the relative-path
21302        // composition against the per-clone-root anchor), a non-ASCII
21303        // byte (a UTF-8 multi-byte name defeating the per-clone-root
21304        // filesystem name resolution on the source-controller pod's
21305        // filesystem layer), or a leading whitespace / dot byte (`" chart"`
21306        // / `".chart"` — surface as either a "directory not found" per-
21307        // CR error or, worse, a silent match against a hidden dot-file
21308        // sibling of the intended chart directory). A future rebrand on
21309        // the canonical lift that lands a value outside the grammar
21310        // would surface here at caixa-core build time on the canonical
21311        // lift, before any renderer consumes the value. Same shape as
21312        // `default_flux_reconcile_interval_is_a_valid_metav1_duration_scalar`
21313        // on the peer canonical-substrate-default-grammar-floor surface.
21314        let v = DEFAULT_FLUX_CHART_SOURCE_SUBPATH;
21315        assert!(
21316            !v.is_empty(),
21317            "DEFAULT_FLUX_CHART_SOURCE_SUBPATH {v:?} must be non-empty \
21318             per the Flux v2 source-controller-side per-CR chart-open \
21319             loop's requirement of a target directory"
21320        );
21321        assert!(
21322            v.is_ascii(),
21323            "DEFAULT_FLUX_CHART_SOURCE_SUBPATH {v:?} must be ASCII \
21324             throughout — a non-ASCII multi-byte name defeats the per-\
21325             clone-root filesystem name resolution on the source-\
21326             controller pod's filesystem layer"
21327        );
21328        let first = v.chars().next().expect("non-empty");
21329        assert!(
21330            !matches!(first, '/' | '.' | ' ' | '\t'),
21331            "DEFAULT_FLUX_CHART_SOURCE_SUBPATH {v:?} first byte {first:?} \
21332             must not be a leading separator (`/`), leading dot (`.`), or \
21333             leading whitespace — a leading separator breaks the relative-\
21334             path composition against the per-clone-root anchor, a leading \
21335             dot risks silent matches against hidden dot-file siblings, and \
21336             leading whitespace defeats the per-clone-root filesystem name \
21337             resolution"
21338        );
21339    }
21340
21341    #[test]
21342    fn flux_helmrelease_remediation_retries_default_pins_canonical_value() {
21343        // Pin the actual scalar so a typo in this lift can't silently
21344        // rebrand the substrate-side default Flux v2
21345        // `HelmRelease.spec.{install,upgrade}.remediation.retries` retry-
21346        // count ceiling the substrate's per-caixa `cluster_bundle`
21347        // renderer seeds into every emitted per-caixa `helmrelease.yaml`
21348        // document under both the install-path and the upgrade-path
21349        // remediation blocks. The value is part of the cluster-side
21350        // contract with the Flux v2 helm-controller (the per-CR
21351        // remediation loop uses this as the ceiling on the number of
21352        // Helm-install / Helm-upgrade re-attempts before the controller
21353        // marks the `HelmRelease` `Ready: False` and stops retrying);
21354        // changing it is a coordinated substrate-side retry-ceiling
21355        // promotion (a `3` → `5` migration once per-caixa idempotency
21356        // invariants tighten and higher-retry recovery from transient
21357        // apiserver / registry / oci-source flakes becomes safe, a `3` →
21358        // `1` migration on hardened per-caixa pipelines where a failed
21359        // apply should escalate to operator-attention rather than mask
21360        // under further retries), not an incidental edit. Peer to
21361        // `default_flux_reconcile_interval_pins_canonical_value` on the
21362        // canonical-Flux-v2-per-CR-substrate-default-scalar pin surface.
21363        assert_eq!(FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT, 3);
21364    }
21365
21366    #[test]
21367    fn flux_helmrelease_remediation_retries_default_is_a_bounded_positive_scalar() {
21368        // Cross-axis invariant: the Flux v2 `HelmRelease.spec.{install,
21369        // upgrade}.remediation.retries` OpenAPI schema types the field
21370        // as a signed 64-bit integer with a documented sentinel `-1`
21371        // meaning "retry indefinitely". The substrate opts out of the
21372        // unbounded-retry sentinel by declaring the canonical default as
21373        // a positive `u32` — the type itself rules out `-1` at
21374        // caixa-core build time, so a future rebrand on this lift cannot
21375        // silently land the "retry forever" sentinel by construction
21376        // (which would let a persistently-failing per-caixa chart apply
21377        // consume Flux v2 helm-controller reconcile-loop cycles
21378        // indefinitely, masking under further retries rather than
21379        // surfacing at the `HelmRelease.status.conditions[]` axis the
21380        // substrate's downstream reconciliation-topology consumer
21381        // watches). Pin the positive-scalar floor + a substrate-side
21382        // "sane retry ceiling" upper bound (the same 100-attempt hard
21383        // cap the peer `POLICY_RETRIES_MAX` per-`:politicas :retries`
21384        // axis carries; a substrate that seeds a per-CR default above
21385        // that ceiling is structurally a footgun by the same
21386        // "unbounded-retry masks the underlying failure" argument that
21387        // motivates the mesh-policy retries cap). Same shape as
21388        // `default_flux_reconcile_interval_is_a_valid_metav1_duration_scalar`
21389        // on the peer canonical-substrate-default-grammar-floor surface.
21390        let v = FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT;
21391        assert!(
21392            v > 0,
21393            "FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT {v} must be strictly \
21394             positive per the substrate's opt-out from the Flux v2 \
21395             `retries: -1` unbounded-retry sentinel — the `u32` type rules \
21396             out the sentinel, and a zero-retries default is structurally \
21397             a `remediation:` sub-block that never fires the retry path it \
21398             is declaring"
21399        );
21400        assert!(
21401            v <= 100,
21402            "FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT {v} must be within \
21403             the substrate's canonical retry-ceiling upper bound (100) — a \
21404             per-CR default above that ceiling silently masks the underlying \
21405             chart-apply failure under further retries rather than surfacing \
21406             it at the `HelmRelease.status.conditions[]` axis the substrate's \
21407             downstream reconciliation-topology consumer watches, the same \
21408             argument that motivates the peer `POLICY_RETRIES_MAX` per-\
21409             `:politicas :retries` axis cap"
21410        );
21411    }
21412
21413    #[test]
21414    fn flux_helmrelease_key_remediation_pins_canonical_value() {
21415        // Pin the actual string so a typo in this lift can't silently
21416        // rebrand the substrate-side Flux v2
21417        // `HelmRelease.spec.{install,upgrade}.remediation` sub-container-
21418        // axis key the substrate's per-caixa `cluster_bundle` renderer
21419        // seeds into every emitted per-caixa `helmrelease.yaml` document
21420        // at both the install-path + upgrade-path per-CR remediation
21421        // sub-block-header positions. The string is part of the cluster-
21422        // side contract with the Flux v2 helm-controller (the controller's
21423        // per-CR remediation loop reaches the retry-cap scalar through
21424        // this exact sub-container axis; a drifted sub-container-key
21425        // silently strips the entire per-path remediation block from the
21426        // emitted per-CR document, leaving the helm-controller to fall
21427        // back to the Flux v2 upstream defaults for the whole remediation
21428        // surface rather than the substrate's chosen ceiling, with no
21429        // diagnostic naming the container-axis-key-drift root cause).
21430        // Changing it is a coordinated Flux v3 CRD-schema-rebrand
21431        // migration alongside the upstream `helm-controller` deprecation
21432        // cycle (candidates like `recovery` / `retryPolicy` /
21433        // `errorHandling` that upstream Flux v3 roadmap floats in the
21434        // migration prose), not an incidental edit. Peer to
21435        // `flux_helmrelease_remediation_retries_default_pins_canonical_value`
21436        // on the sibling scalar-value half + the sibling
21437        // [`FLUX_HELMRELEASE_KEY_RETRIES`] leaf-scalar-key half of the
21438        // same per-path retry-cap declaration triple.
21439        assert_eq!(FLUX_HELMRELEASE_KEY_REMEDIATION, "remediation");
21440    }
21441
21442    #[test]
21443    fn flux_helmrelease_key_remediation_is_a_valid_dns_1123_label() {
21444        // Cross-axis invariant: every Flux v2 `HelmRelease` CRD-schema
21445        // sub-block-header key resolves through the K8s apiserver's
21446        // OpenAPI-schema-side identifier grammar, whose per-field key
21447        // axis is a subset of the DNS-1123-label grammar (lowercase
21448        // alphanumerics + hyphens, non-empty, ≤63 bytes). Pinning the
21449        // canonical `remediation` value against the typed
21450        // [`is_dns_1123_label`] floor rules out grammar drift on this
21451        // lift at caixa-core build time — a future rebrand landing a
21452        // value outside the DNS-1123-label subset (a leading digit, an
21453        // underscore, an uppercase byte, a `.` byte, or empty) would
21454        // surface here on the canonical lift, before any renderer
21455        // consumes the value and before any per-caixa Flux v2 CR reaches
21456        // the apiserver's OpenAPI-schema-side per-field admission gate.
21457        // Same shape as `default_gateway_class_name_is_a_valid_dns_1123_label`
21458        // on the peer canonical-CRD-schema-grammar-floor surface.
21459        assert!(
21460            is_dns_1123_label(FLUX_HELMRELEASE_KEY_REMEDIATION).is_ok(),
21461            "FLUX_HELMRELEASE_KEY_REMEDIATION {FLUX_HELMRELEASE_KEY_REMEDIATION:?} \
21462             must be a valid DNS-1123 label — every K8s apiserver-side \
21463             OpenAPI-schema-per-field-key axis is a subset of that grammar, \
21464             and the Flux v2 `HelmRelease` CRD schema is no exception"
21465        );
21466    }
21467
21468    #[test]
21469    fn flux_helmrelease_key_install_pins_canonical_value() {
21470        // Pin the actual string so a typo in this lift can't silently
21471        // rebrand the Flux v2 `HelmRelease.spec.install` per-CR helm-
21472        // action-phase discriminator parent-container-axis-key the
21473        // rendered `helmrelease.yaml` document mounts its per-CR first-
21474        // time chart apply phase-block under. The string is part of the
21475        // cluster-side contract with the upstream Flux v2 helm-
21476        // controller — the helm-controller's per-CR phase-dispatch loop
21477        // reaches the install-path phase block through this exact parent-
21478        // container axis; a drifted parent-container-key silently strips
21479        // the entire install-path phase block from the emitted per-CR
21480        // document, leaving the helm-controller to fall back to the Flux
21481        // v2 upstream defaults for the whole install-path phase surface
21482        // rather than the substrate's chosen per-CR install-path knob-set
21483        // (the `createNamespace` seeder never fires, the per-CR retry-cap
21484        // ceiling silently drops off the emitted document), with no
21485        // diagnostic naming the phase-discriminator-drift root cause.
21486        // Changing it is a coordinated Flux v3 CRD-schema-rebrand
21487        // migration alongside the upstream `helm-controller` deprecation
21488        // cycle (candidates like `initialize` / `apply` / `create` /
21489        // `first-run` that upstream Flux v3 roadmap floats in the
21490        // migration prose), not an incidental edit. Peer to
21491        // `flux_helmrelease_key_upgrade_pins_canonical_value` on the
21492        // sibling per-CR upgrade-path phase-discriminator parent-
21493        // container-axis-key half of the same per-CR helm-action-phase
21494        // discriminator parent-container-axis-key pair + the sibling
21495        // [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-axis-key
21496        // hosted beneath both parent-container-axis-keys.
21497        assert_eq!(FLUX_HELMRELEASE_KEY_INSTALL, "install");
21498    }
21499
21500    #[test]
21501    fn flux_helmrelease_key_install_is_a_valid_dns_1123_label() {
21502        // Cross-axis invariant: every Flux v2 `HelmRelease` CRD-schema
21503        // sub-block-header key resolves through the K8s apiserver's
21504        // OpenAPI-schema-side identifier grammar, whose per-field key
21505        // axis is a subset of the DNS-1123-label grammar (lowercase
21506        // alphanumerics + hyphens, non-empty, ≤63 bytes). Pinning the
21507        // canonical `install` value against the typed
21508        // [`is_dns_1123_label`] floor rules out grammar drift on this
21509        // lift at caixa-core build time — a future rebrand landing a
21510        // value outside the DNS-1123-label subset (a leading digit, an
21511        // underscore, an uppercase byte, a `.` byte, or empty) would
21512        // surface here on the canonical lift, before any renderer
21513        // consumes the value and before any per-caixa Flux v2 CR reaches
21514        // the apiserver's OpenAPI-schema-side per-field admission gate.
21515        // Same shape as `flux_helmrelease_key_remediation_is_a_valid_
21516        // dns_1123_label` on the sibling per-CR sub-container-axis-key
21517        // grammar-floor surface.
21518        assert!(
21519            is_dns_1123_label(FLUX_HELMRELEASE_KEY_INSTALL).is_ok(),
21520            "FLUX_HELMRELEASE_KEY_INSTALL {FLUX_HELMRELEASE_KEY_INSTALL:?} \
21521             must be a valid DNS-1123 label — every K8s apiserver-side \
21522             OpenAPI-schema-per-field-key axis is a subset of that grammar, \
21523             and the Flux v2 `HelmRelease` CRD schema is no exception"
21524        );
21525    }
21526
21527    #[test]
21528    fn flux_helmrelease_key_upgrade_pins_canonical_value() {
21529        // Pin the actual string so a typo in this lift can't silently
21530        // rebrand the Flux v2 `HelmRelease.spec.upgrade` per-CR helm-
21531        // action-phase discriminator parent-container-axis-key the
21532        // rendered `helmrelease.yaml` document mounts its per-CR
21533        // subsequent-per-version chart re-apply phase-block under. The
21534        // string is part of the cluster-side contract with the upstream
21535        // Flux v2 helm-controller — the helm-controller's per-CR phase-
21536        // dispatch loop reaches the upgrade-path phase block through this
21537        // exact parent-container axis on every per-version chart re-apply
21538        // after the initial install-path phase completes; a drifted
21539        // parent-container-key silently strips the entire upgrade-path
21540        // phase block from the emitted per-CR document, leaving the
21541        // helm-controller to fall back to the Flux v2 upstream defaults
21542        // for the whole upgrade-path phase surface rather than the
21543        // substrate's chosen per-CR upgrade-path knob-set (the
21544        // `remediateLastFailure` toggle never fires, the per-CR retry-
21545        // cap ceiling silently drops off the emitted document), with no
21546        // diagnostic naming the phase-discriminator-drift root cause.
21547        // Changing it is a coordinated Flux v3 CRD-schema-rebrand
21548        // migration alongside the upstream `helm-controller` deprecation
21549        // cycle (candidates like `reapply` / `reconcile` / `update` /
21550        // `promote` that upstream Flux v3 roadmap floats in the
21551        // migration prose), not an incidental edit. Peer to
21552        // `flux_helmrelease_key_install_pins_canonical_value` on the
21553        // sibling per-CR install-path phase-discriminator parent-
21554        // container-axis-key half of the same per-CR helm-action-phase
21555        // discriminator parent-container-axis-key pair.
21556        assert_eq!(FLUX_HELMRELEASE_KEY_UPGRADE, "upgrade");
21557    }
21558
21559    #[test]
21560    fn flux_helmrelease_key_upgrade_is_a_valid_dns_1123_label() {
21561        // Cross-axis invariant: every Flux v2 `HelmRelease` CRD-schema
21562        // sub-block-header key resolves through the K8s apiserver's
21563        // OpenAPI-schema-side identifier grammar, whose per-field key
21564        // axis is a subset of the DNS-1123-label grammar. Pinning the
21565        // canonical `upgrade` value against the typed
21566        // [`is_dns_1123_label`] floor rules out grammar drift on this
21567        // lift at caixa-core build time. Peer to
21568        // `flux_helmrelease_key_install_is_a_valid_dns_1123_label` on
21569        // the sibling install-path phase-discriminator grammar-floor
21570        // surface + `flux_helmrelease_key_remediation_is_a_valid_dns_
21571        // 1123_label` on the sibling per-CR sub-container-axis-key
21572        // grammar-floor surface — same DNS-1123-label subset governs
21573        // every apiserver-side per-field-key axis, so every peer per-CR
21574        // sub-block-header lift carries the same grammar-floor pin.
21575        assert!(
21576            is_dns_1123_label(FLUX_HELMRELEASE_KEY_UPGRADE).is_ok(),
21577            "FLUX_HELMRELEASE_KEY_UPGRADE {FLUX_HELMRELEASE_KEY_UPGRADE:?} \
21578             must be a valid DNS-1123 label — every K8s apiserver-side \
21579             OpenAPI-schema-per-field-key axis is a subset of that grammar, \
21580             and the Flux v2 `HelmRelease` CRD schema is no exception"
21581        );
21582    }
21583
21584    #[test]
21585    fn flux_helmrelease_key_install_and_upgrade_stay_independent_axes() {
21586        // The two per-CR helm-action-phase discriminator parent-
21587        // container-axis-keys name distinct helm-controller-side phases
21588        // — install-path first-time chart apply vs upgrade-path per-
21589        // version chart re-apply — even though both host the same
21590        // sibling [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-
21591        // axis-key beneath them. Pin that the two consts carry distinct
21592        // byte-sequences so a future rebrand on either arm can't
21593        // silently coalesce onto the peer arm (a
21594        // `FLUX_HELMRELEASE_KEY_INSTALL = "upgrade"` typo would flip
21595        // every substrate-side per-CR first-time chart apply phase
21596        // block onto the upgrade-path phase key silently — the install-
21597        // path becomes the upgrade-path at every emit site, and the
21598        // helm-controller reconciles both phase blocks under the same
21599        // parent-container-axis-key, silently dropping either the
21600        // install-path or the upgrade-path per-CR knob-set with no
21601        // diagnostic naming the phase-discriminator-coalesce root
21602        // cause). The per-CR helm-action-phase discriminator pair must
21603        // always resolve to distinct emitted parent-container-keys.
21604        assert_ne!(
21605            FLUX_HELMRELEASE_KEY_INSTALL, FLUX_HELMRELEASE_KEY_UPGRADE,
21606            "the per-CR install-path and upgrade-path helm-action-phase \
21607             discriminator parent-container-axis-keys must remain byte-\
21608             distinct — a coalesce onto one value silently drops either \
21609             the install-path or the upgrade-path per-CR knob-set from \
21610             every emitted `HelmRelease` document"
21611        );
21612    }
21613
21614    #[test]
21615    fn flux_helmrelease_key_remediate_last_failure_pins_canonical_value() {
21616        // Pin the actual string so a typo in this lift can't silently
21617        // rebrand the Flux v2 `HelmRelease.spec.upgrade.remediation
21618        // .remediateLastFailure` upgrade-path-only per-CR remediation-
21619        // toggle leaf-scalar-key the substrate's per-caixa `cluster_bundle`
21620        // renderer seeds to `true` into every emitted per-caixa
21621        // `helmrelease.yaml` document under the sibling
21622        // [`FLUX_HELMRELEASE_KEY_UPGRADE`] per-CR upgrade-path phase-
21623        // discriminator parent-container-axis-key's nested
21624        // [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-axis-key. The
21625        // string is part of the cluster-side contract with the upstream
21626        // Flux v2 helm-controller — the controller's per-CR upgrade-path
21627        // remediation loop reaches the post-retry-exhaustion rollback
21628        // toggle through this exact leaf; a drifted leaf-scalar-key
21629        // silently strips the substrate's chosen post-retry-exhaustion
21630        // rollback semantic from every emitted per-caixa `HelmRelease`
21631        // document, leaving the helm-controller to leave every terminally-
21632        // failed upgrade in the failed state without rolling back to the
21633        // prior last-known-good release the substrate's "no chart apply
21634        // leaves a per-caixa CR in a stalled, unremediated state"
21635        // MESH-COMPOSITION.md §V guarantee mandates, with no diagnostic
21636        // naming the remediation-toggle-drift root cause. Changing it is
21637        // a coordinated Flux v3 CRD-schema-rebrand migration alongside
21638        // the upstream `helm-controller` deprecation cycle (candidates
21639        // like `rollbackOnFailure` / `remediateOnFailure` /
21640        // `recoverLastFailure` that upstream Flux v3 roadmap floats in
21641        // the migration prose), not an incidental edit. Peer to
21642        // `flux_helmrelease_key_retries_pins_canonical_value` on the
21643        // sibling per-CR retry-cap leaf-scalar-key half of the same
21644        // upgrade-path per-CR remediation block leaf-scalar-key pair.
21645        assert_eq!(
21646            FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE,
21647            "remediateLastFailure"
21648        );
21649    }
21650
21651    #[test]
21652    fn flux_helmrelease_key_remediate_last_failure_stays_independent_of_retries() {
21653        // The upgrade-path per-CR remediation block hosts two independent
21654        // leaf-scalar-key axes under the shared sibling
21655        // [`FLUX_HELMRELEASE_KEY_REMEDIATION`] sub-container-axis-key —
21656        // the per-CR retry-cap [`FLUX_HELMRELEASE_KEY_RETRIES`] (that
21657        // also sits under the install-path per-CR remediation block) and
21658        // the upgrade-path-only per-CR remediation-toggle
21659        // [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`]. Pin that the
21660        // two consts carry byte-distinct sequences so a future rebrand
21661        // on either arm can't silently coalesce onto the peer arm (a
21662        // `FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE = "retries"` typo
21663        // would silently rebind the post-retry-exhaustion rollback
21664        // toggle onto the retry-cap ceiling axis at every emit site —
21665        // the helm-controller then reads the substrate's `true` seed as
21666        // an integer retry-cap `1` on the retry-cap axis instead of the
21667        // rollback-on-terminal-failure boolean, silently truncating the
21668        // per-CR upgrade-path retry budget and dropping the rollback
21669        // semantic entirely with no diagnostic naming the leaf-key-
21670        // coalesce root cause). The upgrade-path per-CR remediation
21671        // leaf-scalar-key pair must always resolve to distinct emitted
21672        // leaf-keys.
21673        assert_ne!(
21674            FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE, FLUX_HELMRELEASE_KEY_RETRIES,
21675            "the upgrade-path per-CR remediation retry-cap leaf-scalar-\
21676             key and remediation-toggle leaf-scalar-key must remain \
21677             byte-distinct — a coalesce onto one value silently rebinds \
21678             the post-retry-exhaustion rollback semantic onto the retry-\
21679             cap ceiling axis at every emit site"
21680        );
21681    }
21682
21683    #[test]
21684    fn flux_helmrelease_key_create_namespace_pins_canonical_value() {
21685        // Pin the actual string so a typo in this lift can't silently
21686        // rebrand the Flux v2 `HelmRelease.spec.install.createNamespace`
21687        // install-path-only per-CR namespace-seeder-toggle leaf-scalar-key
21688        // the substrate's per-caixa `cluster_bundle` renderer seeds to
21689        // `true` into every emitted per-caixa `helmrelease.yaml` document
21690        // under the sibling [`FLUX_HELMRELEASE_KEY_INSTALL`] per-CR
21691        // install-path phase-discriminator parent-container-axis-key. The
21692        // string is part of the cluster-side contract with the upstream
21693        // Flux v2 helm-controller — the controller's per-CR install-path
21694        // pre-apply loop reaches the target-namespace-seeder toggle
21695        // through this exact leaf; a drifted leaf-scalar-key silently
21696        // strips the substrate's chosen first-apply namespace-seeder
21697        // semantic from every emitted per-caixa `HelmRelease` document,
21698        // leaving the helm-controller to refuse every first-time per-caixa
21699        // chart apply against a fresh cluster whose target namespace has
21700        // not been pre-provisioned by an out-of-band pipeline the
21701        // substrate's "no per-caixa Servico apply is blocked on manual
21702        // namespace preprovisioning" MESH-COMPOSITION.md §V install-path-
21703        // fluency guarantee mandates, with no diagnostic naming the
21704        // seeder-toggle-drift root cause. Changing it is a coordinated
21705        // Flux v3 CRD-schema-rebrand migration alongside the upstream
21706        // `helm-controller` deprecation cycle (candidates like
21707        // `createTargetNamespace` / `seedNamespace` / `provisionNamespace`
21708        // that upstream Flux v3 roadmap floats in the migration prose),
21709        // not an incidental edit. Peer to
21710        // `flux_helmrelease_key_remediate_last_failure_pins_canonical_value`
21711        // on the sibling mirror-symmetric upgrade-path-only per-CR
21712        // remediation-toggle leaf-scalar-key half of the same install/
21713        // upgrade per-CR phase-specific toggle leaf-scalar-key pair.
21714        assert_eq!(FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE, "createNamespace");
21715    }
21716
21717    #[test]
21718    fn flux_helmrelease_key_create_namespace_stays_independent_of_remediate_last_failure() {
21719        // The per-CR install/upgrade phase blocks host two mirror-symmetric
21720        // phase-specific toggle leaf-scalar-key axes: the install-path-only
21721        // per-CR namespace-seeder-toggle
21722        // [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] under the sibling
21723        // [`FLUX_HELMRELEASE_KEY_INSTALL`] parent-container-axis-key (this
21724        // lift) and the upgrade-path-only per-CR remediation-toggle
21725        // [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7) under the
21726        // sibling [`FLUX_HELMRELEASE_KEY_UPGRADE`] parent-container-axis-key.
21727        // Pin that the two consts carry byte-distinct sequences so a future
21728        // rebrand on either arm can't silently coalesce onto the peer arm
21729        // (a `FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE = "remediateLastFailure"`
21730        // typo would silently rebind the install-path namespace-seeder
21731        // toggle onto the upgrade-path per-CR remediation-toggle leaf at
21732        // every emit site — the helm-controller would then read the
21733        // substrate's `true` seed as a post-retry-exhaustion rollback opt-
21734        // in on the upgrade-path per-CR remediation axis instead of the
21735        // pre-apply namespace-seeder toggle, silently dropping the first-
21736        // apply namespace-seeder semantic entirely and misrouting the
21737        // install-path opt-in onto an upgrade-path axis where it never
21738        // fires with no diagnostic naming the leaf-key-coalesce root
21739        // cause). The install/upgrade per-CR phase-specific toggle leaf-
21740        // scalar-key pair must always resolve to distinct emitted leaf-
21741        // keys under mirror-symmetric parent-container-axis-keys.
21742        assert_ne!(
21743            FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE, FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE,
21744            "the install-path per-CR namespace-seeder-toggle leaf-scalar-\
21745             key and the upgrade-path per-CR remediation-toggle leaf-\
21746             scalar-key must remain byte-distinct — a coalesce onto one \
21747             value silently rebinds one phase's opt-in toggle onto the \
21748             peer phase's opt-in-toggle axis at every emit site, dropping \
21749             the phase-specific pre-apply / post-retry-exhaustion semantic \
21750             the substrate seeds on the coalesced arm"
21751        );
21752    }
21753
21754    #[test]
21755    fn flux_kustomization_key_prune_pins_canonical_value() {
21756        // Pin the actual string so a typo in this lift can't silently
21757        // rebrand the Flux v2 `Kustomization.spec.prune` per-CR garbage-
21758        // collection-toggle leaf-scalar-key the substrate's per-caixa
21759        // `cluster_bundle` renderer seeds to `true` into every emitted
21760        // per-caixa `kustomization.yaml` document at the top-level `spec`
21761        // position. The string is part of the cluster-side contract with
21762        // the upstream Flux v2 kustomize-controller — the controller's
21763        // per-CR reconcile loop reaches the sweep-what-you-removed toggle
21764        // through this exact leaf; a drifted leaf-scalar-key silently
21765        // strips the substrate's chosen sweep-what-you-removed semantic
21766        // from every emitted per-caixa `Kustomization` document, leaving
21767        // per-caixa resources the source manifest set previously
21768        // reconciled but no longer carries dangling in the cluster the
21769        // substrate's "the cluster's per-caixa live state converges to
21770        // the caixa's tatara-lisp source-of-truth on every reconcile —
21771        // resources the source no longer carries are swept by the
21772        // kustomize-controller, not left dangling" CAIXA-SDLC.md §V
21773        // author-to-live-convergence guarantee mandates, with no
21774        // diagnostic naming the toggle-drift root cause. Changing it is
21775        // a coordinated Flux v3 CRD-schema-rebrand migration alongside
21776        // the upstream `kustomize-controller` deprecation cycle
21777        // (candidates like `garbageCollect` / `sweep` / `pruneOrphaned`
21778        // / `deleteOrphans` that upstream Flux v3 roadmap floats in the
21779        // migration prose), not an incidental edit. Peer to
21780        // `flux_helmrelease_key_create_namespace_pins_canonical_value`
21781        // on the sibling co-resident per-caixa `HelmRelease` CR install-
21782        // path per-CR namespace-seeder-toggle leaf-scalar-key half of
21783        // the same per-caixa Flux-bundle per-CR-toggle leaf-scalar-key
21784        // surface.
21785        assert_eq!(FLUX_KUSTOMIZATION_KEY_PRUNE, "prune");
21786    }
21787
21788    #[test]
21789    fn flux_kustomization_key_prune_stays_independent_of_create_namespace() {
21790        // The per-caixa Flux bundle hosts two co-resident per-CR-toggle
21791        // leaf-scalar-key axes: the per-`Kustomization`-CR garbage-
21792        // collection-toggle [`FLUX_KUSTOMIZATION_KEY_PRUNE`] at the
21793        // top-level `spec` position (this lift) and the per-`HelmRelease`-
21794        // CR install-path namespace-seeder-toggle
21795        // [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) under the
21796        // sibling [`FLUX_HELMRELEASE_KEY_INSTALL`] parent-container-axis-
21797        // key. Pin that the two consts carry byte-distinct sequences so
21798        // a future rebrand on either arm can't silently coalesce onto
21799        // the peer arm (a `FLUX_KUSTOMIZATION_KEY_PRUNE = "createNamespace"`
21800        // typo would silently rebind the Kustomization-CR garbage-
21801        // collection-toggle onto the HelmRelease-CR install-path
21802        // namespace-seeder-toggle leaf at every emit site — the
21803        // kustomize-controller would then read the substrate's `true`
21804        // seed at the drifted leaf-key rather than the canonical `prune`
21805        // axis, silently dropping the sweep-what-you-removed semantic
21806        // entirely and leaving per-caixa resources removed from the
21807        // source manifest set dangling in the cluster with no
21808        // diagnostic naming the leaf-key-coalesce root cause). The
21809        // per-`Kustomization`-CR garbage-collection-toggle and the
21810        // per-`HelmRelease`-CR install-path namespace-seeder-toggle must
21811        // always resolve to distinct emitted leaf-keys under their
21812        // respective co-resident per-CR spec surfaces.
21813        assert_ne!(
21814            FLUX_KUSTOMIZATION_KEY_PRUNE, FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE,
21815            "the per-`Kustomization`-CR garbage-collection-toggle leaf-\
21816             scalar-key and the per-`HelmRelease`-CR install-path \
21817             namespace-seeder-toggle leaf-scalar-key must remain byte-\
21818             distinct — a coalesce onto one value silently rebinds one \
21819             CR's opt-in toggle onto the peer CR's opt-in-toggle axis at \
21820             every emit site, dropping the per-CR-specific sweep-what-\
21821             you-removed / pre-apply-namespace-seeder semantic the \
21822             substrate seeds on the coalesced arm"
21823        );
21824    }
21825
21826    #[test]
21827    fn flux_kustomization_prune_default_pins_canonical_value() {
21828        // Pin the actual boolean so a rebrand on this lift can't silently
21829        // rebrand the Flux v2 `Kustomization.spec.prune` per-CR garbage-
21830        // collection-toggle scalar-value seed the substrate's per-caixa
21831        // `cluster_bundle` renderer threads into every emitted per-caixa
21832        // `kustomization.yaml` document under the sibling
21833        // [`FLUX_KUSTOMIZATION_KEY_PRUNE`] leaf-scalar-key axis. The
21834        // scalar is part of the cluster-side contract with the upstream
21835        // Flux v2 kustomize-controller — the controller's per-CR reconcile
21836        // loop reads the scalar under the sibling leaf-scalar-key axis
21837        // to decide whether to garbage-collect resources that were
21838        // previously reconciled by the CR but no longer appear in the
21839        // CR's current desired-state manifest set. Drift from the
21840        // canonical `true` seed to `false` silently drops the substrate's
21841        // chosen sweep-what-you-removed semantic from every emitted
21842        // per-caixa `Kustomization` document, leaving per-caixa resources
21843        // the source manifest set previously reconciled but no longer
21844        // carries dangling in the cluster the substrate's "the cluster's
21845        // per-caixa live state converges to the caixa's tatara-lisp
21846        // source-of-truth on every reconcile — resources the source no
21847        // longer carries are swept by the kustomize-controller, not left
21848        // dangling" CAIXA-SDLC.md §V author-to-live-convergence guarantee
21849        // mandates, with no diagnostic naming the toggle-drift root
21850        // cause. Changing it is a substrate-side policy migration
21851        // (candidates: `true` → `false` on a per-cluster class where a
21852        // human is expected to prune orphaned resources by hand once
21853        // per-cluster policy grows an operator-driven-cleanup mode; a
21854        // per-caixa opt-out slot the ABSORPTION-ROADMAP.md M4 typed-slot
21855        // trajectory adds once the substrate grows a `:kustomization
21856        // :prune` author-side toggle), not an incidental edit. Peer to
21857        // `flux_helmrelease_remediation_retries_default_pins_lifted_value`
21858        // on the sibling per-path per-CR HelmRelease remediation retry-
21859        // cap scalar-value default axis — that default names the per-
21860        // path per-CR remediation retry ceiling, and this default names
21861        // whether the per-CR reconcile loop sweeps orphaned resources at
21862        // all. Both are substrate-side policy choices the operator
21863        // inherits when the per-caixa `ClusterBundleOpts` doesn't pin an
21864        // override.
21865        assert!(FLUX_KUSTOMIZATION_PRUNE_DEFAULT);
21866    }
21867
21868    #[test]
21869    fn flux_kustomization_prune_default_pairs_with_lifted_leaf_key() {
21870        // Sibling-pair pin: the `(leaf-scalar-key, scalar-value)` per-CR
21871        // garbage-collection-toggle declaration lives at two lifted
21872        // `pub const` declarations —
21873        // [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917) on the key half
21874        // and [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] on the value half.
21875        // Both halves must move together on any coordinated Flux v3
21876        // migration (a `garbageCollect: false` rename that rebrands the
21877        // leaf axis onto a new controller-side opt-in vs. the current
21878        // opt-out default; a leaf coalesce onto a peer per-CR toggle
21879        // that reroutes the substrate's canonical scalar seed onto an
21880        // unrelated axis), so a rebrand on either half without a
21881        // coordinated edit on the other would silently split the
21882        // substrate's canonical sweep-what-you-removed declaration —
21883        // the emit-site format-string would still thread the `{prune_key}`
21884        // named-arg through the lifted leaf-scalar-key but pair it with
21885        // a canonical `{prune_default}` that no longer reflects the
21886        // substrate-side semantic the leaf axis names. Pin the pair here
21887        // so a future edit that touches only the leaf-scalar-key half
21888        // or only the scalar-value default half surfaces at build time
21889        // rather than at reconcile time far from the source edit.
21890        // Confirms both consts carry their canonical wire representations
21891        // (`"prune"` byte-string on the leaf-scalar-key half; `true` on
21892        // the scalar-value default half) — the pair as-a-unit reads as
21893        // the substrate's chosen `prune: true` per-CR opt-in.
21894        assert_eq!(FLUX_KUSTOMIZATION_KEY_PRUNE, "prune");
21895        assert!(FLUX_KUSTOMIZATION_PRUNE_DEFAULT);
21896    }
21897
21898    #[test]
21899    fn flux_helmrelease_remediate_last_failure_default_pins_canonical_value() {
21900        // Pin the actual boolean so a rebrand on this lift can't silently
21901        // rebrand the Flux v2 `HelmRelease.spec.upgrade.remediation
21902        // .remediateLastFailure` upgrade-path-only per-CR remediation-toggle
21903        // scalar-value seed the substrate's per-caixa `cluster_bundle`
21904        // renderer threads into every emitted per-caixa `helmrelease.yaml`
21905        // document under the sibling
21906        // [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] leaf-scalar-key
21907        // axis. The scalar is part of the cluster-side contract with the
21908        // upstream Flux v2 helm-controller — the controller's per-CR
21909        // upgrade-path remediation loop reads the scalar under the sibling
21910        // leaf-scalar-key axis to decide whether to trigger the prior-
21911        // release rollback pipeline once the paired
21912        // [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] retry-cap ceiling
21913        // has been exhausted. Drift from the canonical `true` seed to
21914        // `false` silently drops the substrate's chosen post-retry-
21915        // exhaustion rollback semantic from every emitted per-caixa
21916        // `HelmRelease` document, leaving every terminally-failed upgrade
21917        // parked at `Ready: False` without rolling back to the prior last-
21918        // known-good release the substrate's "no chart apply leaves a
21919        // per-caixa CR in a stalled, unremediated state" MESH-COMPOSITION
21920        // .md §V guarantee mandates, with no diagnostic naming the
21921        // remediation-toggle-drift root cause. Changing it is a substrate-
21922        // side policy migration (candidates: `true` → `false` on a per-
21923        // cluster class where terminally-failed upgrades must escalate to
21924        // operator-attention rather than mask under an auto-rollback pipe-
21925        // line; a per-caixa opt-out slot the ABSORPTION-ROADMAP.md M4
21926        // typed-slot trajectory adds once the substrate grows a `:upgrade
21927        // :remediate-last-failure` author-side toggle), not an incidental
21928        // edit. Peer to `flux_kustomization_prune_default_pins_canonical_value`
21929        // on the sibling per-`Kustomization`-CR garbage-collection-toggle
21930        // scalar-value default axis — that default names whether the
21931        // per-CR `Kustomization` reconcile loop sweeps orphaned resources
21932        // at all, and this default names whether the per-CR `HelmRelease`
21933        // upgrade-path remediation loop rolls back to the prior last-
21934        // known-good release once the retry-cap ceiling is exhausted.
21935        // Both are substrate-side policy choices the operator inherits
21936        // when the per-caixa `ClusterBundleOpts` doesn't pin an override.
21937        assert!(FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT);
21938    }
21939
21940    #[test]
21941    fn flux_helmrelease_remediate_last_failure_default_pairs_with_lifted_leaf_key() {
21942        // Sibling-pair pin: the `(leaf-scalar-key, scalar-value)` per-CR
21943        // upgrade-path per-CR post-retry-exhaustion-rollback-toggle
21944        // declaration lives at two lifted `pub const` declarations —
21945        // [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7) on the
21946        // key half and [`FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`]
21947        // on the value half. Both halves must move together on any
21948        // coordinated Flux v3 migration (a `rollbackOnFailure: false`
21949        // rename that rebrands the leaf axis onto a new controller-side
21950        // opt-in vs. the current opt-in default; a leaf coalesce onto a
21951        // peer per-CR toggle that reroutes the substrate's canonical
21952        // scalar seed onto an unrelated axis), so a rebrand on either half
21953        // without a coordinated edit on the other would silently split the
21954        // substrate's canonical post-retry-exhaustion rollback declaration
21955        // — the emit-site format-string would still thread the
21956        // `{remediate_last_failure_key}` named-arg through the lifted
21957        // leaf-scalar-key but pair it with a canonical
21958        // `{remediate_last_failure_default}` that no longer reflects the
21959        // substrate-side semantic the leaf axis names. Pin the pair here
21960        // so a future edit that touches only the leaf-scalar-key half or
21961        // only the scalar-value default half surfaces at build time rather
21962        // than at reconcile time far from the source edit. Confirms both
21963        // consts carry their canonical wire representations
21964        // (`"remediateLastFailure"` byte-string on the leaf-scalar-key
21965        // half; `true` on the scalar-value default half) — the pair as-a-
21966        // unit reads as the substrate's chosen
21967        // `remediateLastFailure: true` per-CR opt-in.
21968        assert_eq!(
21969            FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE,
21970            "remediateLastFailure"
21971        );
21972        assert!(FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT);
21973    }
21974
21975    #[test]
21976    fn flux_helmrelease_create_namespace_default_pins_canonical_value() {
21977        // Pin the actual boolean so a rebrand on this lift can't silently
21978        // rebrand the Flux v2 `HelmRelease.spec.install.createNamespace`
21979        // install-path-only per-CR namespace-seeder-toggle scalar-value
21980        // seed the substrate's per-caixa `cluster_bundle` renderer threads
21981        // into every emitted per-caixa `helmrelease.yaml` document under
21982        // the sibling [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] leaf-
21983        // scalar-key axis. The scalar is part of the cluster-side contract
21984        // with the upstream Flux v2 helm-controller — the controller's
21985        // per-CR install-path pre-apply loop reads the scalar under the
21986        // sibling leaf-scalar-key axis to decide whether to first material-
21987        // ize the target namespace before the first-time chart apply.
21988        // Drift from the canonical `true` seed to `false` silently drops
21989        // the substrate's chosen first-apply namespace-seeder semantic
21990        // from every emitted per-caixa `HelmRelease` document, leaving
21991        // every first-time per-caixa chart apply against a fresh cluster
21992        // refused by the helm-controller because the target namespace was
21993        // not pre-provisioned by an out-of-band pipeline the substrate's
21994        // "no per-caixa Servico apply is blocked on manual namespace
21995        // preprovisioning" MESH-COMPOSITION.md §V install-path-fluency
21996        // guarantee mandates, with no diagnostic naming the seeder-toggle-
21997        // drift root cause. Changing it is a substrate-side policy
21998        // migration (candidates: `true` → `false` on hardened per-cluster
21999        // classes where namespace provisioning is an out-of-band operator
22000        // gate; a per-caixa opt-out slot the ABSORPTION-ROADMAP.md M4
22001        // typed-slot trajectory adds once the substrate grows a `:install
22002        // :create-namespace` author-side toggle), not an incidental edit.
22003        // Peer to `flux_helmrelease_remediate_last_failure_default_pins_canonical_value`
22004        // on the sibling mirror-symmetric upgrade-path-only per-CR
22005        // remediation-toggle scalar-value default axis — that default
22006        // names whether the per-CR `HelmRelease` upgrade-path remediation
22007        // loop rolls back to the prior last-known-good release once the
22008        // retry-cap ceiling is exhausted, and this default names whether
22009        // the per-CR `HelmRelease` install-path pre-apply loop materializes
22010        // the target namespace before the first-time chart apply. Both
22011        // are substrate-side policy choices the operator inherits when
22012        // the per-caixa `ClusterBundleOpts` doesn't pin an override, and
22013        // both close the mirror-symmetric install/upgrade per-CR phase-
22014        // specific toggle scalar-value default pair the peer leaf-scalar-
22015        // key pair [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) /
22016        // [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7)
22017        // already closed on the key half.
22018        assert!(FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT);
22019    }
22020
22021    #[test]
22022    fn flux_helmrelease_create_namespace_default_pairs_with_lifted_leaf_key() {
22023        // Sibling-pair pin: the `(leaf-scalar-key, scalar-value)` per-CR
22024        // install-path per-CR namespace-seeder-toggle declaration lives
22025        // at two lifted `pub const` declarations —
22026        // [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) on the key
22027        // half and [`FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`] on the
22028        // value half. Both halves must move together on any coordinated
22029        // Flux v3 migration (a `createTargetNamespace: false` rename that
22030        // rebrands the leaf axis onto a new controller-side opt-in vs.
22031        // the current opt-in default; a leaf coalesce onto a peer per-CR
22032        // toggle that reroutes the substrate's canonical scalar seed onto
22033        // an unrelated axis), so a rebrand on either half without a
22034        // coordinated edit on the other would silently split the substrate's
22035        // canonical first-apply namespace-seeder declaration — the emit-
22036        // site format-string would still thread the
22037        // `{create_namespace_key}` named-arg through the lifted leaf-
22038        // scalar-key but pair it with a canonical `{create_namespace_default}`
22039        // that no longer reflects the substrate-side semantic the leaf
22040        // axis names. Pin the pair here so a future edit that touches
22041        // only the leaf-scalar-key half or only the scalar-value default
22042        // half surfaces at build time rather than at reconcile time far
22043        // from the source edit. Confirms both consts carry their canonical
22044        // wire representations (`"createNamespace"` byte-string on the
22045        // leaf-scalar-key half; `true` on the scalar-value default half) —
22046        // the pair as-a-unit reads as the substrate's chosen
22047        // `createNamespace: true` per-CR opt-in.
22048        assert_eq!(FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE, "createNamespace");
22049        assert!(FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT);
22050    }
22051
22052    #[test]
22053    fn cluster_bundle_lareira_enabled_default_pins_canonical_value() {
22054        // Pin the actual boolean so a rebrand on this lift can't silently
22055        // rebrand the substrate-side default for the
22056        // `HelmRelease.spec.values.<library>.enabled` child-chart-
22057        // enablement toggle scalar the substrate's per-caixa
22058        // `cluster_bundle` renderer threads into every emitted per-caixa
22059        // `helmrelease.yaml` document under the sibling
22060        // [`HELM_VALUES_KEY_ENABLED`] leaf-scalar-key axis inside the
22061        // per-`{library_name}` values-overlay wrap. The scalar is the
22062        // substrate's chosen "force-on the child chart under the
22063        // cluster_bundle composition path" default — semantically
22064        // distinct from and inverse of the standalone
22065        // [`caixa_helm::RenderOpts`]::`enabled_default = false` seed
22066        // (which renders `enabled: false` in the per-caixa `values.yaml`
22067        // so cluster operators must opt each caixa in per-cluster); the
22068        // `cluster_bundle` composition path is the substrate-side
22069        // opt-in path where the operator has already asserted per-caixa
22070        // cluster-scoped ownership by materializing a per-caixa
22071        // GitRepository + HelmRelease + Kustomization trio, so the
22072        // overlay forces the child chart on by seeding `enabled: true`
22073        // under the `values.<library>` wrap. Drift from the canonical
22074        // `true` seed to `false` silently drops the substrate's chosen
22075        // force-on-under-composition semantic from every emitted
22076        // per-caixa `HelmRelease` document, leaving the paired
22077        // [`DEFAULT_LIBRARY_NAME`] child chart's `enabled: false`
22078        // per-chart default un-overridden — the Helm rendering pipeline
22079        // then no-ops every per-caixa lareira child chart at the
22080        // per-cluster `HelmRelease` apply step, with no diagnostic
22081        // naming the toggle-drift root cause. Peer to the sibling
22082        // `flux_helmrelease_create_namespace_default_pins_canonical_value`
22083        // (be1904b) / `flux_helmrelease_remediate_last_failure_default_pins_canonical_value`
22084        // (be1904b) / `flux_kustomization_prune_default_pins_canonical_value`
22085        // (ea857d8) on the peer canonical-Flux-v2-per-CR-substrate-
22086        // default surface — all four defaults are substrate-side policy
22087        // choices the operator inherits when the per-caixa
22088        // `ClusterBundleOpts` doesn't pin an override.
22089        assert!(CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT);
22090    }
22091
22092    #[test]
22093    fn cluster_bundle_lareira_enabled_default_pairs_with_lifted_leaf_key() {
22094        // Sibling-pair pin: the `(leaf-scalar-key, scalar-value)` per-
22095        // values-overlay child-chart-enablement-toggle declaration lives
22096        // at two lifted `pub const` declarations —
22097        // [`HELM_VALUES_KEY_ENABLED`] on the key half and
22098        // [`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`] on the value half.
22099        // Both halves must move together on any coordinated Helm 4
22100        // migration (an `on: true` rename that rebrands the leaf axis
22101        // onto a new controller-side opt-in vs. the current opt-in
22102        // default; a leaf coalesce onto a peer per-values-block toggle
22103        // that reroutes the substrate's canonical scalar seed onto an
22104        // unrelated axis), so a rebrand on either half without a
22105        // coordinated edit on the other would silently split the
22106        // substrate's canonical force-on-under-composition declaration —
22107        // the emit-site format-string would still thread the
22108        // `{enabled_key}` named-arg through the lifted leaf-scalar-key
22109        // but pair it with a canonical `{lareira_enabled_default}` that
22110        // no longer reflects the substrate-side semantic the leaf axis
22111        // names. Pin the pair here so a future edit that touches only
22112        // the leaf-scalar-key half or only the scalar-value default
22113        // half surfaces at build time rather than at apply time far
22114        // from the source edit. Confirms both consts carry their
22115        // canonical wire representations (`"enabled"` byte-string on
22116        // the leaf-scalar-key half; `true` on the scalar-value default
22117        // half) — the pair as-a-unit reads as the substrate's chosen
22118        // `enabled: true` per-values-overlay opt-in. Peer to
22119        // `flux_kustomization_prune_default_pairs_with_lifted_leaf_key`
22120        // (ea857d8) /
22121        // `flux_helmrelease_create_namespace_default_pairs_with_lifted_leaf_key`
22122        // (be1904b) /
22123        // `flux_helmrelease_remediate_last_failure_default_pairs_with_lifted_leaf_key`
22124        // (be1904b) on the sibling canonical-Flux-v2-per-CR-
22125        // substrate-default paired-halves surfaces.
22126        assert_eq!(HELM_VALUES_KEY_ENABLED, "enabled");
22127        assert!(CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT);
22128    }
22129
22130    #[test]
22131    fn standalone_lareira_enabled_default_pins_canonical_value() {
22132        // Pin the actual boolean so a rebrand on this lift can't silently
22133        // rebrand the substrate-side default for the
22134        // `values.<library>.enabled` child-chart-enablement toggle scalar
22135        // the substrate's per-caixa `caixa_helm::render_chart_for_servico`
22136        // renderer seeds into every emitted per-caixa `values.yaml`
22137        // document under the sibling [`HELM_VALUES_KEY_ENABLED`]
22138        // leaf-scalar-key axis inside the per-`{library_name}` wrap. The
22139        // scalar is the substrate's chosen "leave the child chart opted
22140        // out under the standalone per-chart path" default —
22141        // semantically distinct from and inverse of the composition
22142        // [`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`] seed (which renders
22143        // `enabled: true` in the per-cluster `HelmRelease` values-overlay
22144        // so the substrate force-ons the child chart at bundle
22145        // materialization time); the standalone per-chart path is the
22146        // substrate-side opt-out path where the operator has not yet
22147        // asserted per-caixa cluster-scoped ownership by materializing a
22148        // per-caixa GitRepository + HelmRelease + Kustomization trio, so
22149        // the per-chart `values.yaml` seeds `enabled: false` under the
22150        // `values.<library>` wrap and cluster operators must opt each
22151        // caixa in per-cluster. Drift from the canonical `false` seed to
22152        // `true` silently drops the substrate's chosen
22153        // opt-out-under-standalone semantic from every emitted per-caixa
22154        // `values.yaml` document, force-onning the paired
22155        // [`DEFAULT_LIBRARY_NAME`] child chart against the operator's
22156        // stated per-cluster opt-in convention — every rendered chart's
22157        // library-chart-side workload would come up on `helm template` /
22158        // `helm install` with no diagnostic naming the toggle-drift root
22159        // cause. Peer to `cluster_bundle_lareira_enabled_default_pins_canonical_value`
22160        // on the sibling composition-path `HelmRelease.spec.values.<library>.enabled`
22161        // scalar-value default surface — both defaults are substrate-side
22162        // policy choices the operator inherits when the per-caixa
22163        // `RenderOpts` / `ClusterBundleOpts` doesn't pin an override, and
22164        // together they close the mirror-symmetric standalone / composition
22165        // per-values-block child-chart-enablement-toggle scalar-value
22166        // default pair.
22167        assert!(!STANDALONE_LAREIRA_ENABLED_DEFAULT);
22168    }
22169
22170    #[test]
22171    fn standalone_lareira_enabled_default_pairs_with_lifted_leaf_key() {
22172        // Sibling-pair pin: the `(leaf-scalar-key, scalar-value)` per-
22173        // values-block child-chart-enablement-toggle declaration on the
22174        // standalone per-chart path lives at two lifted `pub const`
22175        // declarations — [`HELM_VALUES_KEY_ENABLED`] on the key half and
22176        // [`STANDALONE_LAREIRA_ENABLED_DEFAULT`] on the value half. Both
22177        // halves must move together on any coordinated Helm 4 migration
22178        // (an `on: false` rename that rebrands the leaf axis onto a new
22179        // controller-side opt-in vs. the current opt-out default; a leaf
22180        // coalesce onto a peer per-values-block toggle that reroutes the
22181        // substrate's canonical scalar seed onto an unrelated axis), so a
22182        // rebrand on either half without a coordinated edit on the other
22183        // would silently split the substrate's canonical
22184        // opt-out-under-standalone declaration — the emit-site block
22185        // insertion would still thread [`HELM_VALUES_KEY_ENABLED`] as the
22186        // key but pair it with a canonical `enabled_default` scalar-value
22187        // seed that no longer reflects the substrate-side semantic the
22188        // leaf axis names. Pin the pair here so a future edit that
22189        // touches only the leaf-scalar-key half or only the scalar-value
22190        // default half surfaces at build time rather than at apply time
22191        // far from the source edit. Confirms both consts carry their
22192        // canonical wire representations (`"enabled"` byte-string on the
22193        // leaf-scalar-key half; `false` on the scalar-value default half)
22194        // — the pair as-a-unit reads as the substrate's chosen
22195        // `enabled: false` per-values-block opt-out. Peer to
22196        // `cluster_bundle_lareira_enabled_default_pairs_with_lifted_leaf_key`
22197        // on the sibling composition-path
22198        // `HelmRelease.spec.values.<library>.enabled` scalar-value default
22199        // paired-halves surface — both `(key, value)` pairs share the same
22200        // [`HELM_VALUES_KEY_ENABLED`] leaf-scalar-key half but diverge on
22201        // the scalar-value half, which is exactly the mirror-symmetric
22202        // standalone / composition path-selection the two scalar-value
22203        // defaults name.
22204        assert_eq!(HELM_VALUES_KEY_ENABLED, "enabled");
22205        assert!(!STANDALONE_LAREIRA_ENABLED_DEFAULT);
22206    }
22207
22208    #[test]
22209    fn standalone_and_cluster_bundle_lareira_enabled_defaults_are_inverse_by_construction() {
22210        // Cross-const coherence pin: the two peer
22211        // per-values-block child-chart-enablement-toggle scalar-value
22212        // defaults on the standalone per-chart path
22213        // ([`STANDALONE_LAREIRA_ENABLED_DEFAULT`]) and the composition
22214        // per-cluster-`HelmRelease` values-overlay path
22215        // ([`CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`]) name mirror-symmetric
22216        // inverse defaults on the same underlying
22217        // `values.<library>.enabled` sub-block axis: the standalone-path
22218        // default is `false` (opt-out — cluster operators must opt each
22219        // caixa in per-cluster) while the composition-path default is
22220        // `true` (opt-in — the substrate force-ons the child chart once
22221        // the operator has asserted per-caixa cluster-scoped ownership by
22222        // materializing a per-caixa GitRepository + HelmRelease +
22223        // Kustomization trio). The inversion is the substrate's chosen
22224        // author-to-live path-selection semantic — every consumer that
22225        // reads either default inherits the per-path opt-out / opt-in
22226        // decision by construction, so a future edit that accidentally
22227        // aligned the two defaults (both `false` on a substrate-wide
22228        // opt-out migration, both `true` on a substrate-wide opt-in
22229        // migration) would silently collapse the substrate's chosen
22230        // standalone-vs-composition path-selection semantic — the
22231        // per-chart `values.yaml` default and the per-cluster
22232        // `HelmRelease.spec.values.<library>.enabled` overlay default
22233        // would agree on the same enablement seed, and either the
22234        // standalone path would force-on the child chart against the
22235        // operator's per-cluster opt-in convention (both `true`) or the
22236        // composition path would leave the child chart opted-out against
22237        // the operator's per-caixa cluster-scoped ownership assertion
22238        // (both `false`). Pin the structural inversion here so a future
22239        // edit that touches only one of the two defaults surfaces at
22240        // caixa-core build time rather than at chart-apply time far from
22241        // the constant-drift source. Confirms the two `bool`s carry
22242        // distinct canonical wire representations — the pair as-a-unit
22243        // reads as the substrate's chosen mirror-symmetric author-to-live
22244        // path-selection semantic (standalone opt-out, composition
22245        // opt-in). Peer to the sibling pairwise-distinctness pins the
22246        // `M3_PLACEMENT_ESTRATEGIA_*` /
22247        // `M2_UPGRADE_INSTRUCTION_KIND_*` closed-set typed-enum
22248        // discriminator axes carry on the peer canonical-typed-enum-
22249        // discriminator distinctness surface.
22250        assert_ne!(
22251            STANDALONE_LAREIRA_ENABLED_DEFAULT, CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT,
22252            "STANDALONE_LAREIRA_ENABLED_DEFAULT and CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT \
22253             must remain inverse `bool`s — the standalone per-chart path defaults to \
22254             opt-out (`false`) and the composition per-cluster-HelmRelease values-overlay \
22255             path defaults to opt-in (`true`); collapsing the inversion silently \
22256             breaks the substrate's chosen mirror-symmetric author-to-live \
22257             path-selection semantic at chart-apply time far from the constant-\
22258             drift source."
22259        );
22260    }
22261
22262    #[test]
22263    fn flux_kustomization_key_path_pins_canonical_value() {
22264        // Pin the actual string so a typo in this lift can't silently
22265        // rebrand the Flux v2 `Kustomization.spec.path` per-CR source-
22266        // sub-tree leaf-scalar-key the substrate's per-caixa
22267        // `cluster_bundle` renderer seeds into every emitted per-caixa
22268        // `kustomization.yaml` document at the top-level `spec`
22269        // position. The string is part of the cluster-side contract
22270        // with the upstream Flux v2 kustomize-controller — the
22271        // controller's per-CR reconcile loop reaches the source-sub-
22272        // tree pointer through this exact leaf; a drifted leaf-scalar-
22273        // key silently unbinds every per-caixa `Kustomization` from
22274        // its paired per-caixa sub-tree of the pleme-io k8s repository
22275        // (the controller defaults to `./` when the CR omits the leaf,
22276        // pulling every unrelated cluster's manifests through the
22277        // wrong per-caixa `Kustomization`), with no diagnostic naming
22278        // the leaf-drift root cause. Changing it is a coordinated Flux
22279        // v3 CRD-schema-rebrand migration alongside the upstream
22280        // `kustomize-controller` deprecation cycle (candidates like
22281        // `sourcePath` / `manifestsPath` / `sourceRoot` upstream Flux
22282        // v3 roadmap floats), not an incidental edit. Peer to
22283        // `flux_kustomization_key_prune_pins_canonical_value` on the
22284        // sibling co-resident per-`Kustomization`-CR `spec.prune`
22285        // garbage-collection-toggle leaf-scalar-key half of the same
22286        // per-`Kustomization`-CR-spec surface.
22287        assert_eq!(FLUX_KUSTOMIZATION_KEY_PATH, "path");
22288    }
22289
22290    #[test]
22291    fn flux_kustomization_key_path_stays_independent_of_prune() {
22292        // The per-`Kustomization`-CR top-level `spec` surface hosts two
22293        // co-resident leaf-scalar-key axes: the per-CR source-sub-tree
22294        // pointer [`FLUX_KUSTOMIZATION_KEY_PATH`] (this lift) and the
22295        // per-CR garbage-collection-toggle [`FLUX_KUSTOMIZATION_KEY_PRUNE`]
22296        // (8ec7917). Pin that the two consts carry byte-distinct
22297        // sequences so a future rebrand on either arm can't silently
22298        // coalesce onto the peer arm (a
22299        // `FLUX_KUSTOMIZATION_KEY_PATH = "prune"` typo would silently
22300        // rebind the substrate's per-cluster / per-caixa sub-tree path
22301        // seed onto the garbage-collection-toggle leaf at every emit
22302        // site — the kustomize-controller would then read the
22303        // substrate's `./clusters/<cluster>/services/<name>` seed as a
22304        // boolean opt-in toggle, silently unbinding the per-caixa
22305        // `Kustomization` from its source-sub-tree entirely with no
22306        // diagnostic naming the leaf-key-coalesce root cause). The
22307        // per-`Kustomization`-CR source-sub-tree pointer and the per-
22308        // `Kustomization`-CR garbage-collection-toggle must always
22309        // resolve to distinct emitted leaf-keys under the same
22310        // top-level `spec` position.
22311        assert_ne!(
22312            FLUX_KUSTOMIZATION_KEY_PATH, FLUX_KUSTOMIZATION_KEY_PRUNE,
22313            "the per-`Kustomization`-CR source-sub-tree leaf-scalar-key \
22314             and the per-`Kustomization`-CR garbage-collection-toggle \
22315             leaf-scalar-key must remain byte-distinct — a coalesce \
22316             onto one value silently rebinds one axis onto the peer \
22317             axis at every emit site, dropping the source-sub-tree / \
22318             sweep-what-you-removed semantic the substrate seeds on the \
22319             coalesced arm"
22320        );
22321    }
22322
22323    #[test]
22324    fn flux_kustomization_key_timeout_pins_canonical_value() {
22325        // Pin the actual string so a typo in this lift can't silently
22326        // rebrand the Flux v2 `Kustomization.spec.timeout` per-CR
22327        // reconcile wall-clock cap leaf-scalar-key the substrate's per-
22328        // caixa `cluster_bundle` renderer seeds into every emitted per-
22329        // caixa `kustomization.yaml` document at the top-level `spec`
22330        // position. The string is part of the cluster-side contract
22331        // with the upstream Flux v2 kustomize-controller — the
22332        // controller's per-CR reconcile loop reaches the wall-clock cap
22333        // through this exact leaf; a drifted leaf-scalar-key silently
22334        // strips the substrate's chosen reconcile-ceiling from every
22335        // emitted per-caixa `Kustomization` document, letting the
22336        // controller fall back to the upstream Flux v2 controller-side
22337        // default cap rather than the substrate's per-caixa
22338        // idempotency-checkpoint-tuned ceiling, with no diagnostic
22339        // naming the timeout-drift root cause. Changing it is a
22340        // coordinated Flux v3 CRD-schema-rebrand migration alongside
22341        // the upstream `kustomize-controller` deprecation cycle, not
22342        // an incidental edit. Peer to
22343        // `flux_kustomization_key_path_pins_canonical_value` and
22344        // `flux_kustomization_key_prune_pins_canonical_value` on the
22345        // sibling co-resident per-`Kustomization`-CR spec surface
22346        // leaf-scalar-key axes.
22347        assert_eq!(FLUX_KUSTOMIZATION_KEY_TIMEOUT, "timeout");
22348    }
22349
22350    #[test]
22351    fn flux_kustomization_key_timeout_stays_independent_of_path_and_prune() {
22352        // The per-`Kustomization`-CR top-level `spec` surface hosts
22353        // three co-resident leaf-scalar-key axes: the per-CR reconcile
22354        // wall-clock cap [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`] (this
22355        // lift), the per-CR source-sub-tree pointer
22356        // [`FLUX_KUSTOMIZATION_KEY_PATH`] (613d7ed), and the per-CR
22357        // garbage-collection-toggle [`FLUX_KUSTOMIZATION_KEY_PRUNE`]
22358        // (8ec7917). Pin that the three consts carry byte-distinct
22359        // sequences so a future rebrand on any one arm can't silently
22360        // coalesce onto a peer arm (a
22361        // `FLUX_KUSTOMIZATION_KEY_TIMEOUT = "path"` typo would silently
22362        // rebind the reconcile wall-clock cap onto the source-sub-tree
22363        // pointer leaf at every emit site — the kustomize-controller
22364        // would then parse the substrate's `./clusters/<c>/services/<n>`
22365        // seed as a `metav1.Duration` scalar and reject the per-CR
22366        // admission gate, with no diagnostic naming the leaf-key-
22367        // coalesce root cause). The per-`Kustomization`-CR reconcile
22368        // wall-clock cap, per-CR source-sub-tree pointer, and per-CR
22369        // garbage-collection-toggle must always resolve to distinct
22370        // emitted leaf-keys under the same top-level `spec` position.
22371        assert_ne!(
22372            FLUX_KUSTOMIZATION_KEY_TIMEOUT, FLUX_KUSTOMIZATION_KEY_PATH,
22373            "the per-`Kustomization`-CR reconcile wall-clock cap leaf-\
22374             scalar-key and the per-`Kustomization`-CR source-sub-tree \
22375             leaf-scalar-key must remain byte-distinct — a coalesce onto \
22376             one value silently rebinds one axis onto the peer axis at \
22377             every emit site, dropping the reconcile-ceiling / source-\
22378             sub-tree semantic the substrate seeds on the coalesced arm"
22379        );
22380        assert_ne!(
22381            FLUX_KUSTOMIZATION_KEY_TIMEOUT, FLUX_KUSTOMIZATION_KEY_PRUNE,
22382            "the per-`Kustomization`-CR reconcile wall-clock cap leaf-\
22383             scalar-key and the per-`Kustomization`-CR garbage-\
22384             collection-toggle leaf-scalar-key must remain byte-distinct \
22385             — a coalesce onto one value silently rebinds one axis onto \
22386             the peer axis at every emit site, dropping the reconcile-\
22387             ceiling / sweep-what-you-removed semantic the substrate \
22388             seeds on the coalesced arm"
22389        );
22390    }
22391
22392    #[test]
22393    fn default_flux_kustomization_timeout_pins_canonical_value() {
22394        // Pin the actual scalar so a typo in this lift can't silently
22395        // rebrand the substrate-side default Flux v2
22396        // `Kustomization.spec.timeout` reconcile wall-clock cap the
22397        // substrate's per-caixa `cluster_bundle` renderer seeds into
22398        // every emitted per-caixa `kustomization.yaml` document at the
22399        // top-level `spec` position. The value is part of the cluster-
22400        // side contract with the Flux v2 kustomize-controller (the
22401        // per-CR reconcile loop uses this as the ceiling on the wall-
22402        // clock time a single reconcile attempt is allowed to consume
22403        // before the controller marks the `Kustomization`
22404        // `Ready: False` and stops retrying); changing it is a
22405        // coordinated substrate-side reconcile-ceiling promotion (a
22406        // `5m` → `3m` migration on faster per-caixa idempotency-
22407        // checkpoint cadence, a `5m` → `10m` migration on larger per-
22408        // caixa manifest sets), not an incidental edit. Peer to
22409        // `default_flux_reconcile_interval_pins_canonical_value` and
22410        // `flux_helmrelease_remediation_retries_default_pins_canonical_value`
22411        // on the canonical-Flux-v2-per-CR-substrate-default-scalar pin
22412        // surface.
22413        assert_eq!(DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT, "5m");
22414    }
22415
22416    #[test]
22417    fn default_flux_kustomization_timeout_is_a_valid_metav1_duration_scalar() {
22418        // Cross-axis grammar invariant: the Flux v2 kustomize-
22419        // controller-side per-CR admission gate parses the reconcile
22420        // wall-clock cap scalar via `metav1.ParseDuration` before
22421        // installing the per-CR watch. The Go-duration-format grammar
22422        // is non-empty, ASCII, and structured as
22423        // `<digits><unit>[<digits><unit>...]` where each unit is one of
22424        // `{ns, us, µs, ms, s, m, h}`. Pin a floor that catches the
22425        // canonical drift footguns — an empty scalar (`""` — admission
22426        // gate rejects), a non-ASCII-alphanumeric byte (`"5 m"` — the
22427        // whitespace defeats the parser), a missing-unit scalar (`"5"`
22428        // — the parser rejects for lack of a unit suffix), or a
22429        // leading-non-digit scalar (`"m5"` — the parser rejects for
22430        // lack of a leading magnitude). A future rebrand on the
22431        // canonical lift that lands a value outside the Go-duration-
22432        // format grammar would surface here at caixa-core build time
22433        // on the canonical lift, before any renderer consumes the
22434        // value. Same shape as
22435        // `default_flux_reconcile_interval_is_a_valid_metav1_duration_scalar`
22436        // on the peer canonical-substrate-default-grammar-floor surface.
22437        let v = DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT;
22438        assert!(
22439            !v.is_empty(),
22440            "DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT {v:?} must be non-empty \
22441             per the Flux v2 controller-side `metav1.ParseDuration` \
22442             admission gate"
22443        );
22444        assert!(
22445            v.chars().all(|c| c.is_ascii_alphanumeric()),
22446            "DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT {v:?} must be ASCII-\
22447             alphanumeric throughout per the Go-duration-format grammar \
22448             — no whitespace / separator bytes the `metav1.ParseDuration` \
22449             admission gate would reject"
22450        );
22451        let first = v.chars().next().expect("non-empty");
22452        assert!(
22453            first.is_ascii_digit(),
22454            "DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT {v:?} first byte {first:?} \
22455             must be an ASCII digit per the Go-duration-format grammar \
22456             — the leading magnitude precedes the unit suffix; a leading \
22457             non-digit defeats `metav1.ParseDuration`"
22458        );
22459        let last = v.chars().next_back().expect("non-empty");
22460        assert!(
22461            last.is_ascii_alphabetic() && last.is_ascii_lowercase(),
22462            "DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT {v:?} last byte {last:?} \
22463             must be an ASCII lowercase alphabetic unit suffix per the \
22464             Go-duration-format grammar — the trailing unit follows the \
22465             magnitude; an unterminated magnitude defeats \
22466             `metav1.ParseDuration`"
22467        );
22468    }
22469
22470    #[test]
22471    fn default_gateway_class_name_pins_canonical_value() {
22472        // Pin the actual string so a typo in this lift can't silently
22473        // rebrand the substrate's chosen K8s Gateway API controller the
22474        // rendered `Gateway`'s `spec.gatewayClassName` axis binds to.
22475        // The string is part of the cluster-side contract with the Cilium
22476        // Gateway API implementation (the Cilium operator watches
22477        // `GatewayClass` objects whose `spec.controllerName` names the
22478        // Cilium reconciler; a drifted `spec.gatewayClassName` on the
22479        // emitted `Gateway` refers to a `GatewayClass` no controller
22480        // reconciles, and the `Gateway` sits at `Programmed: False`
22481        // with every attached `HTTPRoute` unbound), the same eBPF-identity
22482        // data plane the sibling `CiliumNetworkPolicy` renderer emits
22483        // policies against (the mesh-composition "one identity layer,
22484        // one data plane" invariant, MESH-COMPOSITION.md §V), and the
22485        // per-cluster GatewayClass fixture the operator-side install
22486        // pipeline provisions. Changing it is a coordinated multi-repo
22487        // migration (a substrate-side Gateway controller migration to
22488        // Envoy Gateway / Istio Gateway or any per-edition variant),
22489        // not an incidental edit. Peer to
22490        // `default_namespace_pins_canonical_value` and
22491        // `default_flux_system_namespace_pins_canonical_value` on the
22492        // canonical-substrate-default-resource-name-value-pin axis.
22493        assert_eq!(DEFAULT_GATEWAY_CLASS_NAME, "cilium");
22494    }
22495
22496    #[test]
22497    fn default_gateway_class_name_is_a_valid_dns_1123_label() {
22498        // Cross-axis invariant: the Gateway API `GatewayClass` is a
22499        // cluster-scoped K8s resource, and the K8s apiserver enforces
22500        // the DNS-1123 label rule on every cluster-scoped resource's
22501        // `metadata.name`. The emitted `Gateway`'s
22502        // `spec.gatewayClassName` axis references the `GatewayClass`
22503        // resource by that name — a drift to a value the apiserver
22504        // would refuse as a `GatewayClass.metadata.name` couldn't
22505        // resolve at reconcile time either, and the `Gateway`
22506        // Programmed condition never flips true. Pinning this here
22507        // means a future rebrand on the canonical lift can't silently
22508        // land a value the apiserver refuses at the *first* `Gateway`
22509        // apply against a cluster, far from the rebrand commit's
22510        // source — the typed [`is_dns_1123_label`] floor rejects it at
22511        // caixa-core build time on the canonical lift, before any
22512        // renderer consumes the value. Same shape as
22513        // `default_namespace_is_a_valid_dns_1123_label` and
22514        // `default_flux_system_namespace_is_a_valid_dns_1123_label` on
22515        // the peer canonical-DNS-1123-label-floor axes.
22516        assert!(
22517            is_dns_1123_label(DEFAULT_GATEWAY_CLASS_NAME).is_ok(),
22518            "DEFAULT_GATEWAY_CLASS_NAME {DEFAULT_GATEWAY_CLASS_NAME:?} must be a \
22519             valid DNS-1123 label — every K8s apiserver-side schema enforces \
22520             this rule on cluster-scoped `metadata.name` axes, and the \
22521             `Gateway.spec.gatewayClassName` axis resolves by that same rule"
22522        );
22523    }
22524
22525    #[test]
22526    fn flux_helmrelease_api_version_pins_canonical_value() {
22527        // Pin the actual string so a typo in this lift can't silently
22528        // rebrand the Flux v2 `HelmRelease` CRD group/version the rendered
22529        // `helmrelease.yaml` document declares + the rendered
22530        // `kustomization.yaml` document's `healthChecks[].apiVersion`
22531        // axis transitively references. The string is part of the
22532        // cluster-side contract with the Flux v2 `helm-controller` (the
22533        // controller watches the exact `helm.toolkit.fluxcd.io/v2`
22534        // group/version; a drifted value to a stale v2beta1 / v2beta2
22535        // lands the rendered `HelmRelease` outside the controller's
22536        // `Watches` and fails at apply time with "no kind 'HelmRelease'
22537        // is registered for version 'helm.toolkit.fluxcd.io/v2beta2'");
22538        // changing it is a coordinated Flux v3 migration alongside the
22539        // upstream `helm-controller` deprecation cycle, not an
22540        // incidental edit. Peer to `default_flux_system_namespace_pins_canonical_value`
22541        // on the canonical-Flux-CRD-axis-pin axis for the sibling
22542        // [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] constant.
22543        assert_eq!(FLUX_HELMRELEASE_API_VERSION, "helm.toolkit.fluxcd.io/v2");
22544    }
22545
22546    #[test]
22547    fn flux_helmrelease_api_version_carries_group_and_version_segments() {
22548        // Cross-axis invariant: a Kubernetes CRD `apiVersion` is a
22549        // `<group>/<version>` pair separated by exactly one `/` byte.
22550        // The group segment is a DNS-style multi-segment hostname
22551        // (`helm.toolkit.fluxcd.io`) and the version segment is a
22552        // Kubernetes API version label (`v2`, `v2beta1`, `v1alpha1` —
22553        // peer with the K8s API versioning convention upstream
22554        // documents). Pinning this here means a future rebrand on the
22555        // canonical lift can't silently land a malformed apiVersion
22556        // (no `/`, two `/`, empty group, empty version) that every
22557        // downstream YAML-aware deserializer would reject far from the
22558        // rebrand commit's source. The single-`/` invariant is the
22559        // load-bearing K8s API typed-discovery contract: a value the
22560        // apiserver's `RESTMapper` consults to resolve the CRD's
22561        // `RESTKind`.
22562        let v = FLUX_HELMRELEASE_API_VERSION;
22563        let parts: Vec<&str> = v.split('/').collect();
22564        assert_eq!(
22565            parts.len(),
22566            2,
22567            "FLUX_HELMRELEASE_API_VERSION {v:?} must split into exactly two \
22568             `/`-delimited segments (group/version) per the K8s CRD apiVersion \
22569             grammar — every downstream YAML-aware deserializer enforces this \
22570             shape"
22571        );
22572        assert!(
22573            !parts[0].is_empty(),
22574            "FLUX_HELMRELEASE_API_VERSION {v:?} group segment must be non-empty"
22575        );
22576        assert!(
22577            !parts[1].is_empty(),
22578            "FLUX_HELMRELEASE_API_VERSION {v:?} version segment must be non-empty"
22579        );
22580        assert!(
22581            parts[0].contains('.'),
22582            "FLUX_HELMRELEASE_API_VERSION {v:?} group segment {group:?} must be a \
22583             DNS-style multi-segment hostname (the canonical CRD-group convention \
22584             every K8s controller-runtime / kube-rs-aware client expects)",
22585            group = parts[0]
22586        );
22587    }
22588
22589    #[test]
22590    fn default_flux_helmrelease_api_version_matches_caixa_flux_test_fixtures() {
22591        // Cross-file drift pin: the four caixa-flux occurrences of
22592        // `helm.toolkit.fluxcd.io/v2` all consult the same canonical
22593        // constant, but the two `upsert_into_helmrelease_programs` test
22594        // fixtures (caixa-flux/src/lib.rs:928, 970) carry the value as
22595        // a static raw-string literal inside a `serde_yaml::from_str`
22596        // input (the YAML parser is the unit-under-test there, not the
22597        // rendering — the literals are intentionally not threaded
22598        // through the lift). This pin trips at caixa-core build time
22599        // if the canonical constant ever drifts past the literal the
22600        // caixa-flux test fixtures carry, so a future Flux v3 migration
22601        // surfaces here on the canonical-string axis rather than at the
22602        // first failing test fixture far from the rebrand commit. Peer
22603        // to the [`default_flux_system_namespace_pins_canonical_value`]
22604        // pin on the sibling Flux-namespace axis: both pin the canonical
22605        // string at the lift site so a future rebrand lands the
22606        // constant + every downstream reference + every test fixture in
22607        // one coordinated edit.
22608        assert_eq!(
22609            FLUX_HELMRELEASE_API_VERSION, "helm.toolkit.fluxcd.io/v2",
22610            "drift between FLUX_HELMRELEASE_API_VERSION and the \
22611             caixa-flux/src/lib.rs:928,970 test fixtures' literal values; \
22612             coordinate the migration across the const + every fixture in \
22613             one edit"
22614        );
22615    }
22616
22617    #[test]
22618    fn flux_gitrepository_api_version_pins_canonical_value() {
22619        // Pin the actual string so a typo in this lift can't silently
22620        // rebrand the Flux v2 `GitRepository` CRD group/version the rendered
22621        // `gitrepository.yaml` document declares. The string is part of the
22622        // cluster-side contract with the Flux v2 `source-controller` (the
22623        // controller watches the exact `source.toolkit.fluxcd.io/v1`
22624        // group/version; a drifted value to a stale v1beta1 / v1beta2 lands
22625        // the rendered `GitRepository` outside the controller's `Watches`
22626        // and fails at apply time with "no kind 'GitRepository' is
22627        // registered for version 'source.toolkit.fluxcd.io/v1beta2'");
22628        // changing it is a coordinated Flux v3 migration alongside the
22629        // upstream `source-controller` deprecation cycle, not an
22630        // incidental edit. Peer to
22631        // `flux_helmrelease_api_version_pins_canonical_value` on the
22632        // canonical-Flux-CRD-axis-pin axis for the sibling
22633        // [`FLUX_HELMRELEASE_API_VERSION`] constant.
22634        assert_eq!(
22635            FLUX_GITREPOSITORY_API_VERSION,
22636            "source.toolkit.fluxcd.io/v1"
22637        );
22638    }
22639
22640    #[test]
22641    fn flux_gitrepository_api_version_carries_group_and_version_segments() {
22642        // Cross-axis invariant: a Kubernetes CRD `apiVersion` is a
22643        // `<group>/<version>` pair separated by exactly one `/` byte.
22644        // The group segment is a DNS-style multi-segment hostname
22645        // (`source.toolkit.fluxcd.io`) and the version segment is a
22646        // Kubernetes API version label (`v1`, `v1beta1`, `v1alpha1` — peer
22647        // with the K8s API versioning convention upstream documents).
22648        // Pinning this here means a future rebrand on the canonical lift
22649        // can't silently land a malformed apiVersion (no `/`, two `/`,
22650        // empty group, empty version) that every downstream YAML-aware
22651        // deserializer would reject far from the rebrand commit's source.
22652        // The single-`/` invariant is the load-bearing K8s API typed-
22653        // discovery contract: a value the apiserver's `RESTMapper`
22654        // consults to resolve the CRD's `RESTKind`. Peer to
22655        // `flux_helmrelease_api_version_carries_group_and_version_segments`
22656        // on the sibling Flux-CRD-axis.
22657        let v = FLUX_GITREPOSITORY_API_VERSION;
22658        let parts: Vec<&str> = v.split('/').collect();
22659        assert_eq!(
22660            parts.len(),
22661            2,
22662            "FLUX_GITREPOSITORY_API_VERSION {v:?} must split into exactly two \
22663             `/`-delimited segments (group/version) per the K8s CRD apiVersion \
22664             grammar — every downstream YAML-aware deserializer enforces this \
22665             shape"
22666        );
22667        assert!(
22668            !parts[0].is_empty(),
22669            "FLUX_GITREPOSITORY_API_VERSION {v:?} group segment must be non-empty"
22670        );
22671        assert!(
22672            !parts[1].is_empty(),
22673            "FLUX_GITREPOSITORY_API_VERSION {v:?} version segment must be non-empty"
22674        );
22675        assert!(
22676            parts[0].contains('.'),
22677            "FLUX_GITREPOSITORY_API_VERSION {v:?} group segment {group:?} must be a \
22678             DNS-style multi-segment hostname (the canonical CRD-group convention \
22679             every K8s controller-runtime / kube-rs-aware client expects)",
22680            group = parts[0]
22681        );
22682    }
22683
22684    #[test]
22685    fn flux_gitrepository_and_helmrelease_api_versions_share_toolkit_fluxcd_io_root() {
22686        // Cross-axis invariant: every Flux v2 CRD group ends in the canonical
22687        // `.toolkit.fluxcd.io` root the upstream `fluxcd/flux2` project pins
22688        // for the source-/helm-/kustomize-/notification-controller triplet.
22689        // A future Flux v3 promotion that breaks the root suffix (forking
22690        // `source-controller` out of the toolkit group, for example) would
22691        // surface here as a coordinated cross-axis edit-point — both lifted
22692        // constants must move together to preserve the controller-triple
22693        // contract.
22694        const ROOT: &str = ".toolkit.fluxcd.io";
22695        let gr_group = FLUX_GITREPOSITORY_API_VERSION
22696            .split('/')
22697            .next()
22698            .expect("FLUX_GITREPOSITORY_API_VERSION has a group segment");
22699        let hr_group = FLUX_HELMRELEASE_API_VERSION
22700            .split('/')
22701            .next()
22702            .expect("FLUX_HELMRELEASE_API_VERSION has a group segment");
22703        assert!(
22704            gr_group.ends_with(ROOT),
22705            "FLUX_GITREPOSITORY_API_VERSION group {gr_group:?} must end with the \
22706             canonical Flux v2 `{ROOT}` root every controller in the triplet shares"
22707        );
22708        assert!(
22709            hr_group.ends_with(ROOT),
22710            "FLUX_HELMRELEASE_API_VERSION group {hr_group:?} must end with the \
22711             canonical Flux v2 `{ROOT}` root every controller in the triplet shares"
22712        );
22713    }
22714
22715    #[test]
22716    fn flux_kustomization_api_version_pins_canonical_value() {
22717        // Pin the actual string so a typo in this lift can't silently
22718        // rebrand the Flux v2 `Kustomization` CRD group/version the
22719        // rendered `kustomization.yaml` document declares. The string
22720        // is part of the cluster-side contract with the Flux v2
22721        // `kustomize-controller` (the controller watches the exact
22722        // `kustomize.toolkit.fluxcd.io/v1` group/version; a drifted
22723        // value to a stale v1beta1 / v1beta2 lands the rendered
22724        // `Kustomization` outside the controller's `Watches` and
22725        // fails at apply time with "no kind 'Kustomization' is
22726        // registered for version
22727        // 'kustomize.toolkit.fluxcd.io/v1beta2'"); changing it is a
22728        // coordinated Flux v3 migration alongside the upstream
22729        // `kustomize-controller` deprecation cycle, not an
22730        // incidental edit. Peer to
22731        // `flux_helmrelease_api_version_pins_canonical_value` /
22732        // `flux_gitrepository_api_version_pins_canonical_value` on
22733        // the canonical-Flux-CRD-axis-pin axis for the sibling
22734        // [`FLUX_HELMRELEASE_API_VERSION`] /
22735        // [`FLUX_GITREPOSITORY_API_VERSION`] constants — completes
22736        // the Flux v2 controller-triplet's per-CRD-axis pin set.
22737        assert_eq!(
22738            FLUX_KUSTOMIZATION_API_VERSION,
22739            "kustomize.toolkit.fluxcd.io/v1"
22740        );
22741    }
22742
22743    #[test]
22744    fn flux_kustomization_api_version_carries_group_and_version_segments() {
22745        // Cross-axis invariant: a Kubernetes CRD `apiVersion` is a
22746        // `<group>/<version>` pair separated by exactly one `/` byte.
22747        // The group segment is a DNS-style multi-segment hostname
22748        // (`kustomize.toolkit.fluxcd.io`) and the version segment is a
22749        // Kubernetes API version label (`v1`, `v1beta1`, `v1alpha1` —
22750        // peer with the K8s API versioning convention upstream
22751        // documents). Pinning this here means a future rebrand on the
22752        // canonical lift can't silently land a malformed apiVersion
22753        // (no `/`, two `/`, empty group, empty version) that every
22754        // downstream YAML-aware deserializer would reject far from the
22755        // rebrand commit's source. The single-`/` invariant is the
22756        // load-bearing K8s API typed-discovery contract: a value the
22757        // apiserver's `RESTMapper` consults to resolve the CRD's
22758        // `RESTKind`. Peer to
22759        // `flux_helmrelease_api_version_carries_group_and_version_segments`
22760        // / `flux_gitrepository_api_version_carries_group_and_version_segments`
22761        // on the sibling Flux-CRD-axis.
22762        let v = FLUX_KUSTOMIZATION_API_VERSION;
22763        let parts: Vec<&str> = v.split('/').collect();
22764        assert_eq!(
22765            parts.len(),
22766            2,
22767            "FLUX_KUSTOMIZATION_API_VERSION {v:?} must split into exactly two \
22768             `/`-delimited segments (group/version) per the K8s CRD apiVersion \
22769             grammar — every downstream YAML-aware deserializer enforces this \
22770             shape"
22771        );
22772        assert!(
22773            !parts[0].is_empty(),
22774            "FLUX_KUSTOMIZATION_API_VERSION {v:?} group segment must be non-empty"
22775        );
22776        assert!(
22777            !parts[1].is_empty(),
22778            "FLUX_KUSTOMIZATION_API_VERSION {v:?} version segment must be non-empty"
22779        );
22780        assert!(
22781            parts[0].contains('.'),
22782            "FLUX_KUSTOMIZATION_API_VERSION {v:?} group segment {group:?} must be a \
22783             DNS-style multi-segment hostname (the canonical CRD-group convention \
22784             every K8s controller-runtime / kube-rs-aware client expects)",
22785            group = parts[0]
22786        );
22787    }
22788
22789    #[test]
22790    fn flux_controller_triplet_api_versions_share_toolkit_fluxcd_io_root() {
22791        // Cross-axis triplet invariant: the Flux v2 controller triplet
22792        // (source-controller + helm-controller + kustomize-controller)
22793        // upstream all share the canonical `.toolkit.fluxcd.io` root.
22794        // The two-axis sibling pin
22795        // [`flux_gitrepository_and_helmrelease_api_versions_share_toolkit_fluxcd_io_root`]
22796        // enforces the invariant on the source-/helm- pair; this
22797        // pin extends it onto the kustomize-controller axis so a
22798        // future Flux v3 promotion that forks any single controller
22799        // out of the toolkit group surfaces as a coordinated
22800        // cross-axis edit-point across all three constants — the
22801        // controller triplet's CRD group/versions move together
22802        // upstream, and the lift discipline preserves that
22803        // movement at the typed substrate-side `&'static str`
22804        // surface.
22805        const ROOT: &str = ".toolkit.fluxcd.io";
22806        for (name, v) in [
22807            (
22808                "FLUX_GITREPOSITORY_API_VERSION",
22809                FLUX_GITREPOSITORY_API_VERSION,
22810            ),
22811            ("FLUX_HELMRELEASE_API_VERSION", FLUX_HELMRELEASE_API_VERSION),
22812            (
22813                "FLUX_KUSTOMIZATION_API_VERSION",
22814                FLUX_KUSTOMIZATION_API_VERSION,
22815            ),
22816        ] {
22817            let group = v
22818                .split('/')
22819                .next()
22820                .expect("Flux v2 CRD apiVersion has a group segment");
22821            assert!(
22822                group.ends_with(ROOT),
22823                "{name} group {group:?} must end with the canonical Flux v2 \
22824                 `{ROOT}` root every controller in the source/helm/kustomize \
22825                 triplet shares"
22826            );
22827        }
22828    }
22829
22830    #[test]
22831    fn flux_kind_git_repository_pins_canonical_value() {
22832        // Pin the actual string so a typo in this lift can't silently
22833        // rebrand the Flux v2 `GitRepository` CRD `kind` discriminator
22834        // the rendered Flux bundle's three `GitRepository`-naming axes
22835        // declare (gitrepository.yaml top-level kind, helmrelease.yaml
22836        // spec.chart.spec.sourceRef.kind, kustomization.yaml
22837        // spec.sourceRef.kind). The string is part of the cluster-side
22838        // contract with the Flux v2 `source-controller` — the
22839        // apiserver-side CRD resolution contract is the
22840        // `(apiVersion, kind)` tuple keyed against the registered
22841        // `CustomResourceDefinition`, so the kind half of the tuple is
22842        // exactly as load-bearing as the sibling
22843        // [`FLUX_GITREPOSITORY_API_VERSION`] apiVersion half. A drifted
22844        // value (e.g. an upstream Flux v3 rename to `GitSource`) lands
22845        // the rendered documents outside the source-controller's CRD
22846        // registration; changing it is a coordinated Flux v3 migration
22847        // alongside the upstream `source-controller` deprecation cycle,
22848        // not an incidental edit. Peer to
22849        // `flux_gitrepository_api_version_pins_canonical_value` on the
22850        // sibling apiVersion half of the same CRD-lookup tuple.
22851        assert_eq!(FLUX_KIND_GIT_REPOSITORY, "GitRepository");
22852    }
22853
22854    #[test]
22855    fn flux_kind_git_repository_carries_upper_camel_case_shape() {
22856        // Cross-axis invariant: a Kubernetes CRD `kind` discriminator is
22857        // an UpperCamelCase identifier per the K8s API conventions
22858        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds —
22859        // "Kinds are always UpperCamelCase"). Pinning the shape here
22860        // means a future rebrand on the canonical lift can't silently
22861        // land a malformed kind discriminator (snake_case, kebab-case,
22862        // lowercase, empty) that every downstream YAML-aware
22863        // deserializer would reject far from the rebrand commit's
22864        // source. The first-byte uppercase / rest-ASCII-alphanumeric
22865        // invariant is the load-bearing K8s API typed-discovery
22866        // contract: a value the apiserver's `RESTMapper` consults to
22867        // resolve the CRD's `RESTKind`. Peer to
22868        // `flux_gitrepository_api_version_carries_group_and_version_segments`
22869        // on the sibling apiVersion half of the same CRD-lookup tuple.
22870        let v = FLUX_KIND_GIT_REPOSITORY;
22871        assert!(
22872            !v.is_empty(),
22873            "FLUX_KIND_GIT_REPOSITORY {v:?} must be non-empty per the K8s API \
22874             UpperCamelCase kind discriminator grammar"
22875        );
22876        let first = v.chars().next().expect("non-empty");
22877        assert!(
22878            first.is_ascii_uppercase(),
22879            "FLUX_KIND_GIT_REPOSITORY {v:?} first byte {first:?} must be \
22880             ASCII-uppercase per the K8s API UpperCamelCase kind discriminator \
22881             grammar (Kinds are always UpperCamelCase)"
22882        );
22883        assert!(
22884            v.chars().all(|c| c.is_ascii_alphanumeric()),
22885            "FLUX_KIND_GIT_REPOSITORY {v:?} must be ASCII-alphanumeric \
22886             throughout per the K8s API kind discriminator grammar — no \
22887             snake_case, kebab-case, or whitespace bytes the apiserver-side \
22888             RESTMapper would reject"
22889        );
22890    }
22891
22892    #[test]
22893    fn flux_kind_helm_release_pins_canonical_value() {
22894        // Pin the actual string so a typo in this lift can't silently
22895        // rebrand the Flux v2 `HelmRelease` CRD `kind` discriminator
22896        // the rendered Flux bundle's two `HelmRelease`-naming axes
22897        // declare (helmrelease.yaml top-level kind, kustomization.yaml
22898        // spec.healthChecks[].kind). The string is part of the
22899        // cluster-side contract with the Flux v2 `helm-controller` —
22900        // the apiserver-side CRD resolution contract is the
22901        // `(apiVersion, kind)` tuple keyed against the registered
22902        // `CustomResourceDefinition`, so the kind half of the tuple is
22903        // exactly as load-bearing as the sibling
22904        // [`FLUX_HELMRELEASE_API_VERSION`] apiVersion half. A drifted
22905        // value (e.g. an upstream Flux v3 rename to `ChartRelease`)
22906        // lands the rendered documents outside the helm-controller's
22907        // CRD registration; changing it is a coordinated Flux v3
22908        // migration alongside the upstream `helm-controller`
22909        // deprecation cycle, not an incidental edit. Peer to
22910        // `flux_kind_git_repository_pins_canonical_value` on the
22911        // sibling Flux v2 source-controller CRD-`kind` axis.
22912        assert_eq!(FLUX_KIND_HELM_RELEASE, "HelmRelease");
22913    }
22914
22915    #[test]
22916    fn flux_kind_helm_release_carries_upper_camel_case_shape() {
22917        // Cross-axis invariant: a Kubernetes CRD `kind` discriminator is
22918        // an UpperCamelCase identifier per the K8s API conventions
22919        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds —
22920        // "Kinds are always UpperCamelCase"). Pinning the shape here
22921        // means a future rebrand on the canonical lift can't silently
22922        // land a malformed kind discriminator (snake_case, kebab-case,
22923        // lowercase, empty) that every downstream YAML-aware
22924        // deserializer would reject far from the rebrand commit's
22925        // source. The first-byte uppercase / rest-ASCII-alphanumeric
22926        // invariant is the load-bearing K8s API typed-discovery
22927        // contract: a value the apiserver's `RESTMapper` consults to
22928        // resolve the CRD's `RESTKind`. Peer to
22929        // `flux_kind_git_repository_carries_upper_camel_case_shape`
22930        // on the sibling Flux v2 source-controller CRD-`kind` axis.
22931        let v = FLUX_KIND_HELM_RELEASE;
22932        assert!(
22933            !v.is_empty(),
22934            "FLUX_KIND_HELM_RELEASE {v:?} must be non-empty per the K8s API \
22935             UpperCamelCase kind discriminator grammar"
22936        );
22937        let first = v.chars().next().expect("non-empty");
22938        assert!(
22939            first.is_ascii_uppercase(),
22940            "FLUX_KIND_HELM_RELEASE {v:?} first byte {first:?} must be \
22941             ASCII-uppercase per the K8s API UpperCamelCase kind discriminator \
22942             grammar (Kinds are always UpperCamelCase)"
22943        );
22944        assert!(
22945            v.chars().all(|c| c.is_ascii_alphanumeric()),
22946            "FLUX_KIND_HELM_RELEASE {v:?} must be ASCII-alphanumeric \
22947             throughout per the K8s API kind discriminator grammar — no \
22948             snake_case, kebab-case, or whitespace bytes the apiserver-side \
22949             RESTMapper would reject"
22950        );
22951    }
22952
22953    #[test]
22954    fn flux_kind_kustomization_pins_canonical_value() {
22955        // Pin the actual string so a typo in this lift can't silently
22956        // rebrand the Flux v2 `Kustomization` CRD `kind` discriminator
22957        // the rendered `kustomization.yaml`'s top-level `kind` axis
22958        // declares. The string is part of the cluster-side contract
22959        // with the Flux v2 `kustomize-controller` — the apiserver-side
22960        // CRD resolution contract is the `(apiVersion, kind)` tuple
22961        // keyed against the registered `CustomResourceDefinition`, so
22962        // the kind half of the tuple is exactly as load-bearing as the
22963        // sibling [`FLUX_KUSTOMIZATION_API_VERSION`] apiVersion half. A
22964        // drifted value (e.g. an upstream Flux v3 rename to
22965        // `KustomizationSet`) lands the rendered document outside the
22966        // kustomize-controller's CRD registration; changing it is a
22967        // coordinated Flux v3 migration alongside the upstream
22968        // `kustomize-controller` deprecation cycle, not an incidental
22969        // edit. Peer to
22970        // `flux_kind_git_repository_pins_canonical_value` /
22971        // `flux_kind_helm_release_pins_canonical_value` on the sibling
22972        // Flux v2 controller-triplet `kind`-axis surface — completes
22973        // the canonical-Flux-v2-CRD-kind-discriminator pin set across
22974        // the source-controller + helm-controller + kustomize-controller
22975        // triplet.
22976        assert_eq!(FLUX_KIND_KUSTOMIZATION, "Kustomization");
22977    }
22978
22979    #[test]
22980    fn flux_key_source_ref_pins_canonical_value() {
22981        // Pin the actual string so a typo in this lift can't silently
22982        // rebrand the Flux v2 per-`HelmRelease`/`Kustomization`
22983        // source-reference container-axis key the rendered
22984        // `helmrelease.yaml` (`spec.chart.spec.sourceRef`) +
22985        // `kustomization.yaml` (`spec.sourceRef`) documents mount the
22986        // per-CR `(kind, name, namespace)` reference triple under. The
22987        // string is part of the cluster-side contract with every
22988        // Flux-v2-conformant source-controller — the per-CR reconcile
22989        // loop keys off this exact container axis to source the
22990        // `(kind, name, namespace)` reference triple; a drifted value
22991        // (`"source_ref"` / `"source"` / `"sourceReference"` /
22992        // `"gitSourceRef"`) silently dangles both the HelmRelease's
22993        // chart resolution + the parent Kustomization's source
22994        // resolution at the Flux v2 source-controller's CRD
22995        // registration. Changing this value is a coordinated Flux v3
22996        // migration alongside the upstream `fluxcd/flux2` deprecation
22997        // cycle, not an incidental edit. Peer to
22998        // `flux_kind_git_repository_pins_canonical_value` /
22999        // `flux_kind_helm_release_pins_canonical_value` /
23000        // `flux_kind_kustomization_pins_canonical_value` on the sibling
23001        // per-CRD `kind`-axis surface — extends the canonical-Flux-v2-
23002        // load-bearing-string pin discipline from the per-CRD kind
23003        // discriminators onto the sibling per-CR source-reference
23004        // container-axis key both `cluster_bundle` renderers consume.
23005        assert_eq!(FLUX_KEY_SOURCE_REF, "sourceRef");
23006    }
23007
23008    #[test]
23009    fn flux_key_source_ref_carries_lower_camel_case_shape() {
23010        // Cross-axis invariant: the Flux v2 CRD field-naming convention
23011        // (inherited from the upstream K8s API conventions) admits
23012        // lowerCamelCase per-field keys — the source-reference
23013        // container-axis conforms to this on the leading-lowercase
23014        // `sourceRef` shape. Pinning the shape here means a future
23015        // rebrand on the canonical lift can't silently land a malformed
23016        // container-axis key (snake_case, kebab-case, UpperCamelCase,
23017        // empty) that the Flux v2 source-controller's per-CR reconcile
23018        // loop would reject at apply parse time far from the rebrand
23019        // commit's source. Peer to the sibling K8s-CR-lowerCamelCase-
23020        // per-field pin trajectory the sibling `KUBE_KEY_MATCH_LABELS`
23021        // / `GATEWAY_API_KEY_BACKEND_REFS` / `CILIUM_KEY_FROM_ENDPOINTS`
23022        // / `CILIUM_KEY_TO_PORTS` pins established on the sibling per-
23023        // K8s-CR-schema-field-name axes.
23024        let v = FLUX_KEY_SOURCE_REF;
23025        assert!(
23026            !v.is_empty(),
23027            "FLUX_KEY_SOURCE_REF {v:?} must be non-empty per the Flux v2 \
23028             CRD field-naming grammar"
23029        );
23030        let mut chars = v.chars();
23031        assert!(
23032            chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23033            "FLUX_KEY_SOURCE_REF {v:?} must lead with an ASCII-lowercase \
23034             byte per the Flux v2 lowerCamelCase per-CR-field-key convention"
23035        );
23036        assert!(
23037            v.chars().all(|c| c.is_ascii_alphanumeric()),
23038            "FLUX_KEY_SOURCE_REF {v:?} must be ASCII-alphanumeric throughout \
23039             per the Flux v2 lowerCamelCase per-CR-field-key convention — \
23040             no `_` / `-` / `.` / whitespace bytes the Flux v2 source-\
23041             controller's per-CR reconcile loop would reject"
23042        );
23043    }
23044
23045    #[test]
23046    fn flux_key_values_pins_canonical_value() {
23047        // Pin the actual string so a typo in this lift can't silently
23048        // rebrand the Flux v2 per-`HelmRelease` values-override block-
23049        // body-axis key the rendered `helmrelease.yaml`'s `spec.values`
23050        // block declares. The string is part of the cluster-side
23051        // contract with the Flux v2 `helm-controller` — the per-CR
23052        // reconcile loop merges the per-cluster override YAML nested
23053        // under this exact block-body axis into the referenced chart's
23054        // `values.yaml` at Helm-render time; a drifted value
23055        // (`"Values"` / `"vals"` / `"chartValues"` / `"overrides"`)
23056        // silently routes the per-cluster overrides nowhere at Helm
23057        // render, and the workload comes up with the referenced
23058        // chart's admission-time defaults. Changing this value is a
23059        // coordinated Flux v3 migration alongside the upstream
23060        // `fluxcd/flux2` deprecation cycle, not an incidental edit.
23061        // Peer to `flux_key_source_ref_pins_canonical_value` on the
23062        // sibling Flux v2 per-CR container-axis-key surface — extends
23063        // the canonical-Flux-v2-load-bearing-string pin discipline from
23064        // the per-CR source-reference container-axis onto the sibling
23065        // per-`HelmRelease` values-override block-body-axis.
23066        assert_eq!(FLUX_KEY_VALUES, "values");
23067    }
23068
23069    #[test]
23070    fn flux_key_values_carries_lower_camel_case_shape() {
23071        // Cross-axis invariant: the Flux v2 CRD field-naming convention
23072        // (inherited from the upstream K8s API conventions) admits
23073        // lowerCamelCase per-field keys — the values-override block-
23074        // body axis conforms to this on the leading-lowercase `values`
23075        // shape (a single-word lowerCamelCase reduces to all-lowercase).
23076        // Pinning the shape here means a future rebrand on the
23077        // canonical lift can't silently land a malformed block-body-
23078        // axis key (snake_case, kebab-case, UpperCamelCase, empty) that
23079        // the Flux v2 helm-controller's per-CR reconcile loop would
23080        // reject at apply parse time far from the rebrand commit's
23081        // source. Peer to `flux_key_source_ref_carries_lower_camel_case_shape`
23082        // on the sibling Flux v2 per-CR container-axis-key surface.
23083        let v = FLUX_KEY_VALUES;
23084        assert!(
23085            !v.is_empty(),
23086            "FLUX_KEY_VALUES {v:?} must be non-empty per the Flux v2 \
23087             CRD field-naming grammar"
23088        );
23089        let mut chars = v.chars();
23090        assert!(
23091            chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23092            "FLUX_KEY_VALUES {v:?} must lead with an ASCII-lowercase \
23093             byte per the Flux v2 lowerCamelCase per-CR-field-key convention"
23094        );
23095        assert!(
23096            v.chars().all(|c| c.is_ascii_alphanumeric()),
23097            "FLUX_KEY_VALUES {v:?} must be ASCII-alphanumeric throughout \
23098             per the Flux v2 lowerCamelCase per-CR-field-key convention — \
23099             no `_` / `-` / `.` / whitespace bytes the Flux v2 helm-\
23100             controller's per-CR reconcile loop would reject"
23101        );
23102    }
23103
23104    #[test]
23105    fn flux_key_chart_pins_canonical_value() {
23106        // Pin the actual string so a typo in this lift can't silently
23107        // rebrand the Flux v2 per-`HelmRelease` inline-chart-template
23108        // container-axis key the rendered `helmrelease.yaml`'s
23109        // `spec.chart` block declares. The string is part of the
23110        // cluster-side contract with the Flux v2 `helm-controller` —
23111        // the per-CR reconcile loop reads the nested
23112        // `HelmChartTemplate` sub-document (chart-name string,
23113        // source-of-truth reference triple, and reconcile cadence)
23114        // under this exact container axis to source the referenced
23115        // chart at Helm-render time; a drifted value (`"Chart"` /
23116        // `"chartTemplate"` / `"helmChart"` / `"chartRef"`) silently
23117        // dangles the whole chart-template resolution at the helm-
23118        // controller's CRD registration and the referenced chart
23119        // never resolves. Changing this value is a coordinated Flux
23120        // v3 migration alongside the upstream `fluxcd/flux2`
23121        // deprecation cycle, not an incidental edit. Peer to
23122        // `flux_key_source_ref_pins_canonical_value` /
23123        // `flux_key_values_pins_canonical_value` on the sibling Flux
23124        // v2 per-`HelmRelease` body-key surfaces — extends the
23125        // canonical-Flux-v2-load-bearing-string pin discipline from
23126        // the source-reference container-axis + values-override
23127        // block-body-axis onto the sibling chart-template container-
23128        // axis, completing the triplet of Flux v2 per-`HelmRelease`
23129        // `spec.*` body-key pin tests.
23130        assert_eq!(FLUX_KEY_CHART, "chart");
23131    }
23132
23133    #[test]
23134    fn flux_key_chart_carries_lower_camel_case_shape() {
23135        // Cross-axis invariant: the Flux v2 CRD field-naming
23136        // convention (inherited from the upstream K8s API
23137        // conventions) admits lowerCamelCase per-field keys — the
23138        // chart-template container-axis conforms to this on the
23139        // leading-lowercase `chart` shape (a single-word
23140        // lowerCamelCase reduces to all-lowercase). Pinning the shape
23141        // here means a future rebrand on the canonical lift can't
23142        // silently land a malformed container-axis key (snake_case,
23143        // kebab-case, UpperCamelCase, empty) that the Flux v2 helm-
23144        // controller's per-CR reconcile loop would reject at apply
23145        // parse time far from the rebrand commit's source. Peer to
23146        // `flux_key_source_ref_carries_lower_camel_case_shape` /
23147        // `flux_key_values_carries_lower_camel_case_shape` on the
23148        // sibling Flux v2 per-`HelmRelease` body-key surfaces.
23149        let v = FLUX_KEY_CHART;
23150        assert!(
23151            !v.is_empty(),
23152            "FLUX_KEY_CHART {v:?} must be non-empty per the Flux v2 \
23153             CRD field-naming grammar"
23154        );
23155        let mut chars = v.chars();
23156        assert!(
23157            chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23158            "FLUX_KEY_CHART {v:?} must lead with an ASCII-lowercase \
23159             byte per the Flux v2 lowerCamelCase per-CR-field-key convention"
23160        );
23161        assert!(
23162            v.chars().all(|c| c.is_ascii_alphanumeric()),
23163            "FLUX_KEY_CHART {v:?} must be ASCII-alphanumeric throughout \
23164             per the Flux v2 lowerCamelCase per-CR-field-key convention — \
23165             no `_` / `-` / `.` / whitespace bytes the Flux v2 helm-\
23166             controller's per-CR reconcile loop would reject"
23167        );
23168    }
23169
23170    #[test]
23171    fn flux_helmchart_template_key_chart_pins_canonical_value() {
23172        // Pin the actual string so a typo in this lift can't silently
23173        // rebrand the Flux v2 `HelmChartTemplate.spec.chart` per-CR
23174        // chart-NAME reference leaf-scalar-axis key every caixa-flux-
23175        // emitted `HelmRelease` document nests inside the parent
23176        // `spec.chart.spec` sub-document. The helm-controller's
23177        // reconcile pipeline reads the chart-artifact name from this
23178        // exact leaf on every reconcile — a drifted `spec.chart.spec.Chart`
23179        // / `spec.chart.spec.chartRef` / `spec.chart.spec.chartName`
23180        // at the emission-side leaf key would silently land as a well-
23181        // formed but ignored `HelmChartTemplate.spec.*` extra property
23182        // the apiserver's CRD OpenAPI schema permits (arbitrary spec
23183        // extras) and the helm-controller would fail to resolve any
23184        // chart-artifact through the sibling `sourceRef` triple's
23185        // source at reconcile time — a non-self-locating "chart
23186        // 'unknown' not found in <source>" error far from the rebrand
23187        // commit's source `caixa.lisp` / the renderer's format-string
23188        // template. Peer to `flux_key_chart_pins_canonical_value` on
23189        // the sibling per-CR chart-template container-axis parent
23190        // this leaf-scalar-axis lift extends by descending one level
23191        // beneath, closing the substrate-side declaration the parent
23192        // container-axis lift docstring explicitly named as future
23193        // work.
23194        assert_eq!(FLUX_HELMCHART_TEMPLATE_KEY_CHART, "chart");
23195    }
23196
23197    #[test]
23198    fn flux_helmchart_template_key_chart_carries_lower_camel_case_shape() {
23199        // Cross-axis invariant: the Flux v2 CRD field-naming
23200        // convention (inherited from the upstream K8s API conventions)
23201        // admits lowerCamelCase per-field keys — the per-`HelmChartTemplate`
23202        // chart-NAME reference leaf-scalar-axis conforms to this on the
23203        // leading-lowercase `chart` shape (a single-word lowerCamelCase
23204        // reduces to all-lowercase). Pinning the shape here means a
23205        // future rebrand on the canonical lift can't silently land a
23206        // malformed leaf-scalar-axis key (snake_case, kebab-case,
23207        // UpperCamelCase, empty) that the Flux v2 helm-controller's
23208        // per-CR reconcile loop would reject at apply parse time far
23209        // from the rebrand commit's source. Peer to
23210        // `flux_key_chart_carries_lower_camel_case_shape` on the
23211        // sibling per-CR chart-template container-axis parent, and to
23212        // the deliberate axis-independence discipline the sibling
23213        // [`CILIUM_KEY_PATH`] / [`GATEWAY_API_KEY_PATH`] two-CRD-
23214        // groups-sharing-a-string re-exports established (two consts
23215        // spelling the same underlying string at distinct schema
23216        // axes stay sibling constants at the rustc symbol-name axis).
23217        let v = FLUX_HELMCHART_TEMPLATE_KEY_CHART;
23218        assert!(
23219            !v.is_empty(),
23220            "FLUX_HELMCHART_TEMPLATE_KEY_CHART {v:?} must be non-empty per \
23221             the Flux v2 CRD field-naming grammar"
23222        );
23223        let mut chars = v.chars();
23224        assert!(
23225            chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23226            "FLUX_HELMCHART_TEMPLATE_KEY_CHART {v:?} must lead with an \
23227             ASCII-lowercase byte per the Flux v2 lowerCamelCase per-CR-\
23228             field-key convention"
23229        );
23230        assert!(
23231            v.chars().all(|c| c.is_ascii_alphanumeric()),
23232            "FLUX_HELMCHART_TEMPLATE_KEY_CHART {v:?} must be ASCII-\
23233             alphanumeric throughout per the Flux v2 lowerCamelCase per-CR-\
23234             field-key convention — no `_` / `-` / `.` / whitespace bytes \
23235             the Flux v2 helm-controller's per-CR reconcile loop would reject"
23236        );
23237    }
23238
23239    #[test]
23240    fn flux_helmchart_template_key_chart_and_flux_key_chart_stay_independent_axes() {
23241        // Cross-axis independence pin: both `FLUX_HELMCHART_TEMPLATE_KEY_CHART`
23242        // (`spec.chart.spec.chart` chart-NAME reference leaf-scalar-axis)
23243        // and the sibling `FLUX_KEY_CHART` (`spec.chart` per-CR chart-
23244        // template container-axis parent) spell the same underlying
23245        // `"chart"` string today but name distinct schema axes on the
23246        // same Flux v2 `HelmRelease` CRD group (a container-axis parent
23247        // vs a leaf-scalar grandchild inside it). Pin byte-equality of
23248        // each half against its own canonical declaration so a future
23249        // Flux v3 rebrand on either axis lands independently at the
23250        // rustc symbol-name axis rather than coalescing onto one
23251        // canonical declaration through a shared `&'static str`
23252        // allocation Rust's string interner would otherwise fuse.
23253        // Same axis-independence discipline the sibling
23254        // [`CILIUM_KEY_PATH`] (ef6114f) / [`GATEWAY_API_KEY_PATH`]
23255        // (9f45aa4) two-CRD-groups-sharing-a-string re-exports
23256        // established on the peer canonical-axis-independence surface.
23257        assert_eq!(FLUX_HELMCHART_TEMPLATE_KEY_CHART, "chart");
23258        assert_eq!(FLUX_KEY_CHART, "chart");
23259        assert_eq!(FLUX_HELMCHART_TEMPLATE_KEY_CHART, FLUX_KEY_CHART);
23260    }
23261
23262    #[test]
23263    fn flux_key_health_checks_pins_canonical_value() {
23264        // Pin the actual string so a typo in this lift can't silently
23265        // rebrand the Flux v2 per-`Kustomization` health-gate reference-
23266        // list container-axis key the rendered `kustomization.yaml`'s
23267        // `spec.healthChecks` block declares. The string is part of the
23268        // cluster-side contract with the Flux v2 `kustomize-controller`
23269        // — the per-CR reconcile loop reads the nested
23270        // `[]NamespacedObjectKindReference` list under this exact
23271        // container axis to gate the parent `Kustomization`'s
23272        // `Ready=True` transition on the referenced sibling
23273        // `HelmRelease` reaching its `HelmReleaseReady=True` condition;
23274        // a drifted value (`"HealthChecks"` / `"healthchecks"` /
23275        // `"healthcheck"` / `"health_checks"` / `"probes"`) silently
23276        // dangles the parent `Kustomization` at `Reconciling` forever
23277        // at the kustomize-controller's health-gate evaluation, and the
23278        // dependent per-cluster fleet-programs upsert chain never sees
23279        // `Ready=True`. Changing this value is a coordinated Flux v3
23280        // migration alongside the upstream `fluxcd/flux2` deprecation
23281        // cycle, not an incidental edit. Peer to
23282        // `flux_key_source_ref_pins_canonical_value` /
23283        // `flux_key_chart_pins_canonical_value` /
23284        // `flux_key_values_pins_canonical_value` on the sibling Flux v2
23285        // body-key surfaces — extends the canonical-Flux-v2-load-bearing-
23286        // string pin discipline from the per-`HelmRelease` triplet
23287        // (`spec.chart` + `spec.chart.spec.sourceRef` + `spec.values`)
23288        // onto the sibling per-`Kustomization` `spec.healthChecks`
23289        // reference-list container-axis, completing the quartet of Flux
23290        // v2 `spec.*` body-key pin tests.
23291        assert_eq!(FLUX_KEY_HEALTH_CHECKS, "healthChecks");
23292    }
23293
23294    #[test]
23295    fn flux_key_health_checks_carries_lower_camel_case_shape() {
23296        // Cross-axis invariant: the Flux v2 CRD field-naming convention
23297        // (inherited from the upstream K8s API conventions) admits
23298        // lowerCamelCase per-field keys — the per-`Kustomization`
23299        // health-gate reference-list container-axis conforms to this on
23300        // the leading-lowercase `healthChecks` shape. Pinning the shape
23301        // here means a future rebrand on the canonical lift can't
23302        // silently land a malformed container-axis key (snake_case,
23303        // kebab-case, UpperCamelCase, empty) that the Flux v2 kustomize-
23304        // controller's per-CR reconcile loop would reject at apply
23305        // parse time far from the rebrand commit's source. Peer to
23306        // `flux_key_source_ref_carries_lower_camel_case_shape` /
23307        // `flux_key_chart_carries_lower_camel_case_shape` /
23308        // `flux_key_values_carries_lower_camel_case_shape` on the
23309        // sibling Flux v2 body-key surfaces.
23310        let v = FLUX_KEY_HEALTH_CHECKS;
23311        assert!(
23312            !v.is_empty(),
23313            "FLUX_KEY_HEALTH_CHECKS {v:?} must be non-empty per the Flux \
23314             v2 CRD field-naming grammar"
23315        );
23316        let mut chars = v.chars();
23317        assert!(
23318            chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23319            "FLUX_KEY_HEALTH_CHECKS {v:?} must lead with an ASCII-\
23320             lowercase byte per the Flux v2 lowerCamelCase per-CR-field-\
23321             key convention"
23322        );
23323        assert!(
23324            v.chars().all(|c| c.is_ascii_alphanumeric()),
23325            "FLUX_KEY_HEALTH_CHECKS {v:?} must be ASCII-alphanumeric \
23326             throughout per the Flux v2 lowerCamelCase per-CR-field-key \
23327             convention — no `_` / `-` / `.` / whitespace bytes the Flux \
23328             v2 kustomize-controller's per-CR reconcile loop would reject"
23329        );
23330    }
23331
23332    #[test]
23333    fn flux_key_interval_pins_canonical_value() {
23334        // Pin the actual string so a typo in this lift can't silently
23335        // rebrand the Flux v2 per-CR reconcile-poll cadence scalar-axis
23336        // key the rendered Flux bundle's three `spec.interval` scalars
23337        // declare — the shared axis-key the source-controller, helm-
23338        // controller, and kustomize-controller each read to schedule
23339        // their per-CR poll cycles off the sibling per-CR `apiVersion` +
23340        // `kind` registration. A drifted value (`"Interval"` / `"period"`
23341        // / `"cadence"` / `"pollInterval"` / `"reconcileInterval"`)
23342        // silently drops the per-CR reconcile schedule from all three
23343        // Flux controllers' per-CR watch registrations simultaneously —
23344        // the referenced Git source never re-polls / the referenced
23345        // chart never re-templates / the parent Kustomization never
23346        // re-applies at upstream drift, freezing the whole cluster's
23347        // per-`caixa` per-cluster bundle at the last-applied snapshot.
23348        // Changing this value is a coordinated Flux v3 migration
23349        // alongside the upstream `fluxcd/flux2` deprecation cycle, not
23350        // an incidental edit. Peer to
23351        // `flux_key_source_ref_pins_canonical_value` /
23352        // `flux_key_chart_pins_canonical_value` /
23353        // `flux_key_values_pins_canonical_value` /
23354        // `flux_key_health_checks_pins_canonical_value` on the sibling
23355        // Flux v2 per-CR body-key surfaces — extends the canonical-Flux-
23356        // v2-load-bearing-string pin discipline from the per-CR body-key
23357        // quartet onto the sibling cross-CR-shared reconcile-poll
23358        // cadence scalar-axis every Flux v2 controller reads.
23359        assert_eq!(FLUX_KEY_INTERVAL, "interval");
23360    }
23361
23362    #[test]
23363    fn flux_key_interval_carries_lower_camel_case_shape() {
23364        // Cross-axis invariant: the Flux v2 CRD field-naming convention
23365        // (inherited from the upstream K8s API conventions) admits
23366        // lowerCamelCase per-field keys — the per-CR reconcile-poll
23367        // cadence scalar-axis conforms to this on the leading-lowercase
23368        // `interval` shape. Pinning the shape here means a future rebrand
23369        // on the canonical lift can't silently land a malformed scalar-
23370        // axis key (snake_case, kebab-case, UpperCamelCase, empty) that
23371        // any of the three Flux v2 controllers' per-CR reconcile loops
23372        // would reject at apply parse time far from the rebrand commit's
23373        // source. Peer to `flux_key_source_ref_carries_lower_camel_case_shape`
23374        // / `flux_key_chart_carries_lower_camel_case_shape` /
23375        // `flux_key_values_carries_lower_camel_case_shape` /
23376        // `flux_key_health_checks_carries_lower_camel_case_shape` on the
23377        // sibling Flux v2 per-CR body-key surfaces.
23378        let v = FLUX_KEY_INTERVAL;
23379        assert!(
23380            !v.is_empty(),
23381            "FLUX_KEY_INTERVAL {v:?} must be non-empty per the Flux \
23382             v2 CRD field-naming grammar"
23383        );
23384        let mut chars = v.chars();
23385        assert!(
23386            chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23387            "FLUX_KEY_INTERVAL {v:?} must lead with an ASCII-\
23388             lowercase byte per the Flux v2 lowerCamelCase per-CR-field-\
23389             key convention"
23390        );
23391        assert!(
23392            v.chars().all(|c| c.is_ascii_alphanumeric()),
23393            "FLUX_KEY_INTERVAL {v:?} must be ASCII-alphanumeric \
23394             throughout per the Flux v2 lowerCamelCase per-CR-field-key \
23395             convention — no `_` / `-` / `.` / whitespace bytes any of \
23396             the three Flux v2 controllers' per-CR reconcile loops would \
23397             reject"
23398        );
23399    }
23400
23401    #[test]
23402    fn flux_gitrepository_ref_key_tag_pins_canonical_value() {
23403        // Pin the actual string so a typo in this lift can't silently
23404        // rebrand the Flux v2 per-`GitRepository` `spec.ref.tag`
23405        // git-tag-selector scalar-axis key the rendered
23406        // `gitrepository.yaml` document declares on the tag-arm of the
23407        // FluxCD source-controller `spec.ref` discriminated-union axis.
23408        // A drifted value (`"Tag"` / `"gitTag"` / `"tagName"`) silently
23409        // dangles the tag-arm sub-block at the FluxCD source-controller's
23410        // CRD registration; the per-Servico clone never resolves at
23411        // reconcile time. Peer to
23412        // `flux_gitrepository_ref_key_branch_pins_canonical_value` /
23413        // `flux_gitrepository_ref_key_commit_pins_canonical_value` on
23414        // the sibling per-shape arms of the same discriminated-union
23415        // axis — closes the three-arm sub-selector-key trio the
23416        // FluxCD source-controller reads to bind the per-CR git-source
23417        // clone refspec.
23418        assert_eq!(FLUX_GITREPOSITORY_REF_KEY_TAG, "tag");
23419    }
23420
23421    #[test]
23422    fn flux_gitrepository_ref_key_branch_pins_canonical_value() {
23423        // Peer of `flux_gitrepository_ref_key_tag_pins_canonical_value`
23424        // on the branch-arm of the FluxCD source-controller
23425        // `GitRepository.spec.ref` discriminated-union axis.
23426        assert_eq!(FLUX_GITREPOSITORY_REF_KEY_BRANCH, "branch");
23427    }
23428
23429    #[test]
23430    fn flux_gitrepository_ref_key_commit_pins_canonical_value() {
23431        // Peer of `flux_gitrepository_ref_key_tag_pins_canonical_value`
23432        // on the commit-arm of the FluxCD source-controller
23433        // `GitRepository.spec.ref` discriminated-union axis.
23434        assert_eq!(FLUX_GITREPOSITORY_REF_KEY_COMMIT, "commit");
23435    }
23436
23437    #[test]
23438    fn flux_gitrepository_key_ref_pins_canonical_value() {
23439        // Bridge-arm pin: [`FLUX_GITREPOSITORY_KEY_REF`] resolves to
23440        // the canonical `"ref"` byte today — the exact YAML key the
23441        // FluxCD `source-controller` reads on every rendered
23442        // `GitRepository` document's `spec.ref` container-axis to
23443        // source the per-CR git-clone refspec discriminated-union
23444        // arm (`{tag, branch, commit}`). Pin the literal here (peer
23445        // with the sibling
23446        // [`flux_gitrepository_ref_key_tag_pins_canonical_value`] /
23447        // [`flux_gitrepository_ref_key_branch_pins_canonical_value`] /
23448        // [`flux_gitrepository_ref_key_commit_pins_canonical_value`]
23449        // per-shape arm sub-selector pins on the same `spec.ref`
23450        // sub-schema) so a future Flux v3 sub-schema rebrand on the
23451        // parent container-axis surfaces here as a coordinated edit-
23452        // point at the definition site rather than a silent apply-
23453        // time split between the writer-side template composer and
23454        // the aggregator's per-CR `RESTMapper` reader.
23455        assert_eq!(FLUX_GITREPOSITORY_KEY_REF, "ref");
23456    }
23457
23458    #[test]
23459    fn flux_gitrepository_key_url_pins_canonical_value() {
23460        // Bridge-arm pin: [`FLUX_GITREPOSITORY_KEY_URL`] resolves to
23461        // the canonical `"url"` byte today — the exact YAML key the
23462        // FluxCD `source-controller` reads on every rendered
23463        // `GitRepository` document's `spec.url` leaf-scalar-axis to
23464        // source the per-CR git-remote clone target. Pin the literal
23465        // here (peer with the sibling
23466        // [`flux_gitrepository_key_ref_pins_canonical_value`] on the
23467        // per-CR `spec.ref` container-axis surface) so a future Flux
23468        // v3 sub-schema rebrand on the URL axis (e.g. an upstream
23469        // `fluxcd/flux2` rename of `spec.url` to `spec.gitUrl` /
23470        // `spec.repository`) surfaces here as a coordinated edit-
23471        // point at the definition site rather than a silent apply-
23472        // time split between the writer-side template composer and
23473        // the source-controller's per-CR `RESTMapper` reader.
23474        assert_eq!(FLUX_GITREPOSITORY_KEY_URL, "url");
23475    }
23476
23477    #[test]
23478    fn flux_gitrepository_key_url_stays_independent_of_ref_and_api_version() {
23479        // Cross-axis peer-independence pin: the per-`GitRepository`-CRD
23480        // canonical-load-bearing-string surface carries three distinct
23481        // axes on the same CRD — `apiVersion`
23482        // ([`FLUX_GITREPOSITORY_API_VERSION`], the CRD-group/version
23483        // half of the `(apiVersion, kind)` apiserver-side CRD-lookup
23484        // tuple), `spec.ref`
23485        // ([`FLUX_GITREPOSITORY_KEY_REF`], the per-CR ref-selection
23486        // container-axis), and `spec.url`
23487        // ([`FLUX_GITREPOSITORY_KEY_URL`], the per-CR remote-repo-URL
23488        // leaf-scalar-axis). These three constants spell mutually
23489        // distinct schema axes on the same Flux v2 `source-controller`
23490        // CRD; pinning distinctness here means a future rebrand on
23491        // any one axis (a Flux v3 CRD-version bump, a `spec.ref`
23492        // container-axis rename, or a `spec.url` schema promotion)
23493        // surfaces as an edit on the corresponding canonical const
23494        // alone, without silently collapsing the three axes into one
23495        // edit-point at the rustc symbol-name axis.
23496        assert_ne!(FLUX_GITREPOSITORY_KEY_URL, FLUX_GITREPOSITORY_KEY_REF);
23497        assert_ne!(FLUX_GITREPOSITORY_KEY_URL, FLUX_GITREPOSITORY_API_VERSION);
23498    }
23499
23500    #[test]
23501    fn flux_gitrepository_ref_keys_all_carry_lower_camel_case_shape() {
23502        // Cross-axis invariant on all three arms of the FluxCD
23503        // source-controller `GitRepository.spec.ref` discriminated-union
23504        // axis: the Flux v2 CRD field-naming convention (inherited from
23505        // the upstream K8s API conventions) admits lowerCamelCase
23506        // per-field keys — `tag` / `branch` / `commit` all conform.
23507        // Pinning the shape here means a future rebrand on any of the
23508        // three canonical lifts can't silently land a malformed
23509        // sub-selector key (snake_case, kebab-case, UpperCamelCase,
23510        // empty) that the Flux v2 source-controller's per-CR reconcile
23511        // loop would reject at apply parse time. Peer to
23512        // `flux_key_interval_carries_lower_camel_case_shape` on the
23513        // sibling per-CR reconcile-poll-cadence scalar-axis key surface.
23514        for v in [
23515            FLUX_GITREPOSITORY_REF_KEY_TAG,
23516            FLUX_GITREPOSITORY_REF_KEY_BRANCH,
23517            FLUX_GITREPOSITORY_REF_KEY_COMMIT,
23518        ] {
23519            assert!(
23520                !v.is_empty(),
23521                "FLUX_GITREPOSITORY_REF_KEY_* {v:?} must be non-empty \
23522                 per the Flux v2 CRD field-naming grammar"
23523            );
23524            let mut chars = v.chars();
23525            assert!(
23526                chars.next().is_some_and(|c| c.is_ascii_lowercase()),
23527                "FLUX_GITREPOSITORY_REF_KEY_* {v:?} must lead with an \
23528                 ASCII-lowercase byte per the Flux v2 lowerCamelCase \
23529                 per-CR-field-key convention"
23530            );
23531            assert!(
23532                v.chars().all(|c| c.is_ascii_alphanumeric()),
23533                "FLUX_GITREPOSITORY_REF_KEY_* {v:?} must be ASCII-\
23534                 alphanumeric throughout per the Flux v2 lowerCamelCase \
23535                 per-CR-field-key convention — no `_` / `-` / `.` / \
23536                 whitespace bytes the Flux v2 source-controller's per-CR \
23537                 reconcile loop would reject"
23538            );
23539        }
23540    }
23541
23542    #[test]
23543    fn flux_gitrepository_ref_keys_are_pairwise_distinct() {
23544        // The three arms of the FluxCD source-controller
23545        // `GitRepository.spec.ref` discriminated-union axis must remain
23546        // pairwise distinct — a hypothetical drift that collapsed two
23547        // sub-selector keys onto the same byte-string (e.g. an
23548        // accidental copy-paste making TAG and BRANCH both spell
23549        // `"tag"`) would silently reroute the per-shape emit at
23550        // `caixa_flux::GitRefSpec::ref_field_name` dispatch time and
23551        // dangle one arm's rendered `spec.ref` sub-block at cluster-
23552        // apply time. Pin the pairwise-distinctness here so the drift
23553        // fires at test time, not at cluster-apply time far from the
23554        // drift site.
23555        let keys = [
23556            FLUX_GITREPOSITORY_REF_KEY_TAG,
23557            FLUX_GITREPOSITORY_REF_KEY_BRANCH,
23558            FLUX_GITREPOSITORY_REF_KEY_COMMIT,
23559        ];
23560        for (i, a) in keys.iter().enumerate() {
23561            for b in keys.iter().skip(i + 1) {
23562                assert_ne!(
23563                    a, b,
23564                    "FLUX_GITREPOSITORY_REF_KEY_* arms must be pairwise \
23565                     distinct (got a duplicate: {a:?})"
23566                );
23567            }
23568        }
23569    }
23570
23571    #[test]
23572    fn flux_kind_kustomization_carries_upper_camel_case_shape() {
23573        // Cross-axis invariant: a Kubernetes CRD `kind` discriminator is
23574        // an UpperCamelCase identifier per the K8s API conventions
23575        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds —
23576        // "Kinds are always UpperCamelCase"). Pinning the shape here
23577        // means a future rebrand on the canonical lift can't silently
23578        // land a malformed kind discriminator (snake_case, kebab-case,
23579        // lowercase, empty) that every downstream YAML-aware
23580        // deserializer would reject far from the rebrand commit's
23581        // source. The first-byte uppercase / rest-ASCII-alphanumeric
23582        // invariant is the load-bearing K8s API typed-discovery
23583        // contract: a value the apiserver's `RESTMapper` consults to
23584        // resolve the CRD's `RESTKind`. Peer to
23585        // `flux_kind_git_repository_carries_upper_camel_case_shape` /
23586        // `flux_kind_helm_release_carries_upper_camel_case_shape` on
23587        // the sibling Flux v2 controller-triplet `kind`-axis surface.
23588        let v = FLUX_KIND_KUSTOMIZATION;
23589        assert!(
23590            !v.is_empty(),
23591            "FLUX_KIND_KUSTOMIZATION {v:?} must be non-empty per the K8s API \
23592             UpperCamelCase kind discriminator grammar"
23593        );
23594        let first = v.chars().next().expect("non-empty");
23595        assert!(
23596            first.is_ascii_uppercase(),
23597            "FLUX_KIND_KUSTOMIZATION {v:?} first byte {first:?} must be \
23598             ASCII-uppercase per the K8s API UpperCamelCase kind discriminator \
23599             grammar (Kinds are always UpperCamelCase)"
23600        );
23601        assert!(
23602            v.chars().all(|c| c.is_ascii_alphanumeric()),
23603            "FLUX_KIND_KUSTOMIZATION {v:?} must be ASCII-alphanumeric \
23604             throughout per the K8s API kind discriminator grammar — no \
23605             snake_case, kebab-case, or whitespace bytes the apiserver-side \
23606             RESTMapper would reject"
23607        );
23608    }
23609
23610    #[test]
23611    fn gateway_api_api_version_pins_canonical_value() {
23612        // Pin the actual string so a typo in this lift can't silently
23613        // rebrand the K8s SIG-Network Gateway API CRD group/version
23614        // the rendered `Gateway` / `HTTPRoute` documents declare. The
23615        // string is part of the cluster-side contract with the
23616        // upstream Gateway-API-conformant gateway implementation
23617        // (Cilium, Istio, Envoy Gateway, NGINX, et al.): the
23618        // apiserver-side CRD-version registration watches the exact
23619        // `gateway.networking.k8s.io/v1` group/version; a drifted
23620        // value to a stale v1beta1 / v1alpha2 lands the rendered
23621        // `Gateway` / `HTTPRoute` outside the registration and fails
23622        // at apply time with "no kind 'Gateway' is registered for
23623        // version 'gateway.networking.k8s.io/v1beta1'"; changing it
23624        // is a coordinated Gateway API GA promotion alongside the
23625        // upstream SIG-Network deprecation cycle, not an incidental
23626        // edit. Peer to `flux_kustomization_api_version_pins_canonical_value`
23627        // / `flux_helmrelease_api_version_pins_canonical_value` /
23628        // `flux_gitrepository_api_version_pins_canonical_value` on
23629        // the canonical-K8s-CRD-axis-pin axis for the sibling
23630        // Flux v2 controller-triplet constants — extends the
23631        // canonical-string-pin discipline from the cluster-side
23632        // Flux v2 reconcile contract onto the cluster-side K8s
23633        // Gateway API ingress contract.
23634        assert_eq!(GATEWAY_API_API_VERSION, "gateway.networking.k8s.io/v1");
23635    }
23636
23637    #[test]
23638    fn gateway_api_api_version_carries_group_and_version_segments() {
23639        // Cross-axis invariant: a Kubernetes CRD `apiVersion` is a
23640        // `<group>/<version>` pair separated by exactly one `/` byte.
23641        // The group segment is a DNS-style multi-segment hostname
23642        // (`gateway.networking.k8s.io`) and the version segment is a
23643        // Kubernetes API version label (`v1`, `v1beta1`, `v1alpha2` —
23644        // peer with the K8s API versioning convention upstream
23645        // documents). Pinning this here means a future rebrand on the
23646        // canonical lift can't silently land a malformed apiVersion
23647        // (no `/`, two `/`, empty group, empty version) that every
23648        // downstream YAML-aware deserializer would reject far from the
23649        // rebrand commit's source. The single-`/` invariant is the
23650        // load-bearing K8s API typed-discovery contract: a value the
23651        // apiserver's `RESTMapper` consults to resolve the CRD's
23652        // `RESTKind`. Peer to
23653        // `flux_kustomization_api_version_carries_group_and_version_segments`
23654        // / `flux_helmrelease_api_version_carries_group_and_version_segments`
23655        // / `flux_gitrepository_api_version_carries_group_and_version_segments`
23656        // on the sibling Flux v2 controller-triplet CRD-axes.
23657        let v = GATEWAY_API_API_VERSION;
23658        let parts: Vec<&str> = v.split('/').collect();
23659        assert_eq!(
23660            parts.len(),
23661            2,
23662            "GATEWAY_API_API_VERSION {v:?} must split into exactly two \
23663             `/`-delimited segments (group/version) per the K8s CRD apiVersion \
23664             grammar — every downstream YAML-aware deserializer enforces this \
23665             shape"
23666        );
23667        assert!(
23668            !parts[0].is_empty(),
23669            "GATEWAY_API_API_VERSION {v:?} group segment must be non-empty"
23670        );
23671        assert!(
23672            !parts[1].is_empty(),
23673            "GATEWAY_API_API_VERSION {v:?} version segment must be non-empty"
23674        );
23675        assert!(
23676            parts[0].contains('.'),
23677            "GATEWAY_API_API_VERSION {v:?} group segment {group:?} must be a \
23678             DNS-style multi-segment hostname (the canonical CRD-group convention \
23679             every K8s controller-runtime / kube-rs-aware client expects)",
23680            group = parts[0]
23681        );
23682    }
23683
23684    #[test]
23685    fn cilium_api_version_pins_canonical_value() {
23686        // Pin the actual string so a typo in this lift can't silently
23687        // rebrand the Cilium CRD group/version the rendered
23688        // `CiliumNetworkPolicy` document declares. The string is part
23689        // of the cluster-side contract with the upstream Cilium
23690        // operator: the Cilium-operator-side CRD-version registration
23691        // watches the exact `cilium.io/v2` group/version; a drifted
23692        // value to a stale `v2alpha1` lands the rendered
23693        // `CiliumNetworkPolicy` outside the registration and fails at
23694        // apply time with "no kind 'CiliumNetworkPolicy' is registered
23695        // for version 'cilium.io/v2alpha1'"; changing it is a
23696        // coordinated Cilium-CRD promotion alongside the upstream
23697        // Cilium deprecation cycle, not an incidental edit. Peer to
23698        // `gateway_api_api_version_pins_canonical_value` /
23699        // `flux_kustomization_api_version_pins_canonical_value` /
23700        // `flux_helmrelease_api_version_pins_canonical_value` /
23701        // `flux_gitrepository_api_version_pins_canonical_value` on
23702        // the canonical-K8s-CRD-axis-pin axis for the sibling
23703        // K8s Gateway API + Flux v2 controller-triplet constants —
23704        // extends the canonical-string-pin discipline from the
23705        // cluster-side K8s Gateway API ingress + Flux v2 reconcile
23706        // contracts onto the cluster-side Cilium identity-based mesh
23707        // contract.
23708        assert_eq!(CILIUM_API_VERSION, "cilium.io/v2");
23709    }
23710
23711    #[test]
23712    fn cilium_api_version_carries_group_and_version_segments() {
23713        // Cross-axis invariant: a Kubernetes CRD `apiVersion` is a
23714        // `<group>/<version>` pair separated by exactly one `/` byte.
23715        // The group segment is a DNS-style hostname (`cilium.io`) and
23716        // the version segment is a Kubernetes API version label (`v2`,
23717        // `v2alpha1` — peer with the K8s API versioning convention
23718        // upstream documents). Pinning this here means a future rebrand
23719        // on the canonical lift can't silently land a malformed
23720        // apiVersion (no `/`, two `/`, empty group, empty version) that
23721        // every downstream YAML-aware deserializer would reject far
23722        // from the rebrand commit's source. The single-`/` invariant
23723        // is the load-bearing K8s API typed-discovery contract: a value
23724        // the apiserver's `RESTMapper` consults to resolve the CRD's
23725        // `RESTKind`. Peer to
23726        // `gateway_api_api_version_carries_group_and_version_segments`
23727        // / `flux_kustomization_api_version_carries_group_and_version_segments`
23728        // / `flux_helmrelease_api_version_carries_group_and_version_segments`
23729        // / `flux_gitrepository_api_version_carries_group_and_version_segments`
23730        // on the sibling K8s Gateway API + Flux v2 controller-triplet
23731        // CRD-axes.
23732        let v = CILIUM_API_VERSION;
23733        let parts: Vec<&str> = v.split('/').collect();
23734        assert_eq!(
23735            parts.len(),
23736            2,
23737            "CILIUM_API_VERSION {v:?} must split into exactly two \
23738             `/`-delimited segments (group/version) per the K8s CRD apiVersion \
23739             grammar — every downstream YAML-aware deserializer enforces this \
23740             shape"
23741        );
23742        assert!(
23743            !parts[0].is_empty(),
23744            "CILIUM_API_VERSION {v:?} group segment must be non-empty"
23745        );
23746        assert!(
23747            !parts[1].is_empty(),
23748            "CILIUM_API_VERSION {v:?} version segment must be non-empty"
23749        );
23750        assert!(
23751            parts[0].contains('.'),
23752            "CILIUM_API_VERSION {v:?} group segment {group:?} must be a \
23753             DNS-style hostname (the canonical CRD-group convention \
23754             every K8s controller-runtime / kube-rs-aware client expects)",
23755            group = parts[0]
23756        );
23757    }
23758
23759    #[test]
23760    fn cilium_kind_network_policy_pins_canonical_value() {
23761        // Pin the actual string so a typo in this lift can't silently
23762        // rebrand the Cilium-operator-side `CiliumNetworkPolicy` CRD
23763        // `kind` discriminator the rendered CNP document's top-level
23764        // `kind` axis declares. The string is part of the cluster-side
23765        // contract with the upstream Cilium operator — the apiserver-side
23766        // CRD resolution contract is the `(apiVersion, kind)` tuple
23767        // keyed against the registered `CustomResourceDefinition`, so
23768        // the kind half of the tuple is exactly as load-bearing as the
23769        // sibling [`CILIUM_API_VERSION`] apiVersion half. A drifted
23770        // value (e.g. an upstream rename to `CiliumNetworkPolicyV2`)
23771        // lands the rendered document outside the Cilium operator's
23772        // CRD registration; changing it is a coordinated Cilium-CRD
23773        // promotion alongside the upstream Cilium deprecation cycle,
23774        // not an incidental edit. Peer to
23775        // `flux_kind_kustomization_pins_canonical_value` /
23776        // `flux_kind_helm_release_pins_canonical_value` /
23777        // `flux_kind_git_repository_pins_canonical_value` on the
23778        // sibling cluster-side-CRD-`kind`-discriminator pin set —
23779        // extends the canonical-string-pin discipline from the Flux v2
23780        // controller-triplet `kind`-axis surface onto the Cilium-CRD
23781        // `kind`-axis surface, completing the per-Cilium-CRD
23782        // kind+apiVersion canonical-pin pair the M3 Aplicacao mesh
23783        // renderer's eBPF data-plane contract rests on.
23784        assert_eq!(CILIUM_KIND_NETWORK_POLICY, "CiliumNetworkPolicy");
23785    }
23786
23787    #[test]
23788    fn cilium_kind_network_policy_carries_upper_camel_case_shape() {
23789        // Cross-axis invariant: a Kubernetes CRD `kind` discriminator is
23790        // an UpperCamelCase identifier per the K8s API conventions
23791        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds —
23792        // "Kinds are always UpperCamelCase"). Pinning the shape here
23793        // means a future rebrand on the canonical lift can't silently
23794        // land a malformed kind discriminator (snake_case, kebab-case,
23795        // lowercase, empty) that every downstream YAML-aware
23796        // deserializer would reject far from the rebrand commit's
23797        // source. The first-byte uppercase / rest-ASCII-alphanumeric
23798        // invariant is the load-bearing K8s API typed-discovery
23799        // contract: a value the apiserver's `RESTMapper` consults to
23800        // resolve the CRD's `RESTKind`. Peer to
23801        // `flux_kind_kustomization_carries_upper_camel_case_shape` /
23802        // `flux_kind_helm_release_carries_upper_camel_case_shape` /
23803        // `flux_kind_git_repository_carries_upper_camel_case_shape` on
23804        // the sibling cluster-side-CRD-`kind`-discriminator surface.
23805        let v = CILIUM_KIND_NETWORK_POLICY;
23806        assert!(
23807            !v.is_empty(),
23808            "CILIUM_KIND_NETWORK_POLICY {v:?} must be non-empty per the K8s API \
23809             UpperCamelCase kind discriminator grammar"
23810        );
23811        let first = v.chars().next().expect("non-empty");
23812        assert!(
23813            first.is_ascii_uppercase(),
23814            "CILIUM_KIND_NETWORK_POLICY {v:?} first byte {first:?} must be \
23815             ASCII-uppercase per the K8s API UpperCamelCase kind discriminator \
23816             grammar (Kinds are always UpperCamelCase)"
23817        );
23818        assert!(
23819            v.chars().all(|c| c.is_ascii_alphanumeric()),
23820            "CILIUM_KIND_NETWORK_POLICY {v:?} must be ASCII-alphanumeric \
23821             throughout per the K8s API kind discriminator grammar — no \
23822             snake_case, kebab-case, or whitespace bytes the apiserver-side \
23823             RESTMapper would reject"
23824        );
23825    }
23826
23827    #[test]
23828    fn cilium_key_to_ports_pins_canonical_value() {
23829        // Pin the actual string so a typo in this lift can't silently
23830        // rebrand the Cilium CNP `spec.ingress[].toPorts[]` per-ingress-
23831        // rule port-set-container-axis key the rendered CNP document
23832        // mounts its per-port-set `{ports: […], rules: {…}}` list under.
23833        // The string is part of the cluster-side contract with the
23834        // upstream Cilium operator — the Cilium-operator-side per-CNP
23835        // L4/L7-dispatch pass keys off this axis to route the per-port
23836        // set through the eBPF data-plane's L4-allow (via `ports`) /
23837        // L7-dispatch (via nested `rules`) branches; a drifted value
23838        // (`"toport"` / `"toPort"` / `"targetPorts"`) at either the
23839        // production emitter or a downstream renderer's per-ingress-rule
23840        // port-set upsert silently emits a per-ingress-rule entry whose
23841        // port-set container the Cilium CRD schema validator drops as
23842        // unknown, and every intra-mesh `:contratos` flow the affected
23843        // CNP was authored to allow drops at the eBPF data-plane's
23844        // default-deny gate. Changing this value is a coordinated
23845        // Cilium-CRD promotion alongside the upstream Cilium project's
23846        // CRD schema-migration cycle, not an incidental edit. Peer to
23847        // `kube_key_rules_pins_canonical_value` (the nested
23848        // `spec.ingress[].toPorts[].rules` axis-key pin the L7-dispatch
23849        // container nests inside this port-set container's each entry)
23850        // on the sibling per-CNP-dispatch-axis pin set — completes the
23851        // per-CNP L4/L7-dispatch-container `(toPorts, rules)` pin pair
23852        // the M3 Aplicacao mesh renderer's eBPF data-plane contract
23853        // rests on.
23854        assert_eq!(CILIUM_KEY_TO_PORTS, "toPorts");
23855    }
23856
23857    #[test]
23858    fn cilium_key_to_ports_carries_lower_camel_case_shape() {
23859        // Cross-axis invariant: a Kubernetes CRD schema field name is a
23860        // lowerCamelCase identifier per the K8s API conventions
23861        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
23862        // "Field names should be lowercase camelCase") — first byte
23863        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
23864        // kebab-case or whitespace. Pinning the shape here means a
23865        // future rebrand on the canonical lift can't silently land a
23866        // malformed field-name discriminator (snake_case, kebab-case,
23867        // UpperCamelCase, empty) that the apiserver-side CRD schema
23868        // validator would reject far from the rebrand commit's source.
23869        // The first-byte lowercase / rest-ASCII-alphanumeric invariant
23870        // is the load-bearing K8s API typed-schema contract: a value
23871        // the apiserver-side OpenAPI schema validator consults to
23872        // resolve each CR-field's typed slot. Peer to the sibling
23873        // per-CNP `kind`-axis
23874        // `cilium_kind_network_policy_carries_upper_camel_case_shape`
23875        // pin — the UpperCamelCase K8s discriminator grammar governs
23876        // the top-level `kind` axis, the lowerCamelCase K8s field-name
23877        // grammar governs every nested schema-field axis (including
23878        // this per-ingress-rule port-set-container-axis key), same
23879        // convention distinct grammars.
23880        let v = CILIUM_KEY_TO_PORTS;
23881        assert!(
23882            !v.is_empty(),
23883            "CILIUM_KEY_TO_PORTS {v:?} must be non-empty per the K8s API \
23884             lowerCamelCase field-name grammar"
23885        );
23886        let first = v.chars().next().expect("non-empty");
23887        assert!(
23888            first.is_ascii_lowercase(),
23889            "CILIUM_KEY_TO_PORTS {v:?} first byte {first:?} must be \
23890             ASCII-lowercase per the K8s API lowerCamelCase field-name \
23891             grammar (field names are always lowerCamelCase)"
23892        );
23893        assert!(
23894            v.chars().all(|c| c.is_ascii_alphanumeric()),
23895            "CILIUM_KEY_TO_PORTS {v:?} must be ASCII-alphanumeric \
23896             throughout per the K8s API field-name grammar — no \
23897             snake_case, kebab-case, or whitespace bytes the apiserver-side \
23898             OpenAPI schema validator would reject"
23899        );
23900    }
23901
23902    #[test]
23903    fn cilium_key_endpoint_selector_pins_canonical_value() {
23904        // Pin the actual string so a typo in this lift can't silently
23905        // rebrand the Cilium CNP `spec.endpointSelector` destination-
23906        // identity-axis key the rendered CNP document mounts its
23907        // L3-target `LabelSelector` under. The string is part of the
23908        // cluster-side contract with the upstream Cilium operator —
23909        // the Cilium-operator-side per-CNP identity-resolution pass
23910        // keys off this axis to bind the emitted policy against its
23911        // destination workload identity via the K8s LabelSelector
23912        // schema; a drifted value (`"endpointselector"` /
23913        // `"endpointSelectors"` / `"endpoints"`) at either the
23914        // production emitter or a downstream renderer's per-CNP
23915        // destination-identity upsert silently emits a CNP whose
23916        // destination-identity axis the Cilium CRD schema validator
23917        // drops as unknown, and the policy binds against no
23918        // destination pods — every intra-mesh `:contratos` flow the
23919        // affected CNP was authored to allow drops at the eBPF
23920        // data-plane's default-deny gate. Changing this value is a
23921        // coordinated Cilium-CRD promotion alongside the upstream
23922        // Cilium project's CRD schema-migration cycle, not an
23923        // incidental edit. Peer to `cilium_key_to_ports_pins_\
23924        // canonical_value` (the per-ingress-rule port-set container
23925        // axis-key pin the L3-target selector pairs with under the
23926        // shared per-CNP-body schema) on the sibling per-CNP-body-axis
23927        // pin set — completes the per-CNP L3/L4/L7-triad
23928        // `(endpointSelector, ingress → toPorts → rules)` pin set the
23929        // M3 Aplicacao mesh renderer's eBPF data-plane contract rests
23930        // on.
23931        assert_eq!(CILIUM_KEY_ENDPOINT_SELECTOR, "endpointSelector");
23932    }
23933
23934    #[test]
23935    fn cilium_key_endpoint_selector_carries_lower_camel_case_shape() {
23936        // Cross-axis invariant: a Kubernetes CRD schema field name is a
23937        // lowerCamelCase identifier per the K8s API conventions
23938        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
23939        // "Field names should be lowercase camelCase") — first byte
23940        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
23941        // kebab-case or whitespace. Pinning the shape here means a
23942        // future rebrand on the canonical lift can't silently land a
23943        // malformed field-name discriminator (snake_case, kebab-case,
23944        // UpperCamelCase, empty) that the apiserver-side CRD schema
23945        // validator would reject far from the rebrand commit's source.
23946        // Peer to `cilium_key_to_ports_carries_lower_camel_case_shape`
23947        // on the sibling per-CNP-body-axis grammar-pin set — the
23948        // lowerCamelCase K8s field-name grammar governs every nested
23949        // schema-field axis (including this per-CNP destination-
23950        // identity-axis key), same convention.
23951        let v = CILIUM_KEY_ENDPOINT_SELECTOR;
23952        assert!(
23953            !v.is_empty(),
23954            "CILIUM_KEY_ENDPOINT_SELECTOR {v:?} must be non-empty per the K8s API \
23955             lowerCamelCase field-name grammar"
23956        );
23957        let first = v.chars().next().expect("non-empty");
23958        assert!(
23959            first.is_ascii_lowercase(),
23960            "CILIUM_KEY_ENDPOINT_SELECTOR {v:?} first byte {first:?} must be \
23961             ASCII-lowercase per the K8s API lowerCamelCase field-name \
23962             grammar (field names are always lowerCamelCase)"
23963        );
23964        assert!(
23965            v.chars().all(|c| c.is_ascii_alphanumeric()),
23966            "CILIUM_KEY_ENDPOINT_SELECTOR {v:?} must be ASCII-alphanumeric \
23967             throughout per the K8s API field-name grammar — no \
23968             snake_case, kebab-case, or whitespace bytes the apiserver-side \
23969             OpenAPI schema validator would reject"
23970        );
23971    }
23972
23973    #[test]
23974    fn cilium_key_ingress_pins_canonical_value() {
23975        // Pin the actual string so a typo in this lift can't silently
23976        // rebrand the Cilium CNP `spec.ingress[]` traffic-direction
23977        // container-axis key the rendered CNP document mounts its
23978        // permitted per-`(:de, :para)` inbound-ingress-rule list under.
23979        // The string is part of the cluster-side contract with the
23980        // upstream Cilium operator — the Cilium-operator-side per-CNP
23981        // L4/L7-dispatch pass keys off this axis to route the per-CNP
23982        // ingress-rule list through the eBPF data-plane's inbound-
23983        // traffic dispatch branch; a drifted value (`"Ingress"` /
23984        // `"ingressRules"` / `"inbound"`) at either the production
23985        // emitter or a downstream renderer's per-CNP traffic-direction
23986        // upsert silently emits a CNP whose ingress-rule list the
23987        // Cilium CRD schema validator drops as unknown, and every
23988        // intra-mesh `:contratos` flow the affected CNP was authored to
23989        // allow drops at the eBPF data-plane's default-deny gate.
23990        // Changing this value is a coordinated Cilium-CRD promotion
23991        // alongside the upstream Cilium project's CRD schema-migration
23992        // cycle, not an incidental edit. Peer to
23993        // `cilium_key_endpoint_selector_pins_canonical_value` (the
23994        // destination-identity axis-key pin the traffic-direction
23995        // container axis-key sits alongside under the shared per-CNP-
23996        // body schema) + `cilium_key_to_ports_pins_canonical_value`
23997        // (the per-ingress-rule port-set container axis-key pin the
23998        // traffic-direction axis nests) on the sibling per-CNP-body-
23999        // axis pin set — completes the per-CNP L3/L4/L7-triad
24000        // `(endpointSelector, ingress → toPorts → rules)` pin set the
24001        // M3 Aplicacao mesh renderer's eBPF data-plane contract rests
24002        // on.
24003        assert_eq!(CILIUM_KEY_INGRESS, "ingress");
24004    }
24005
24006    #[test]
24007    fn cilium_key_ingress_carries_lower_camel_case_shape() {
24008        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24009        // lowerCamelCase identifier per the K8s API conventions
24010        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24011        // "Field names should be lowercase camelCase") — first byte
24012        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24013        // kebab-case or whitespace. Pinning the shape here means a
24014        // future rebrand on the canonical lift can't silently land a
24015        // malformed field-name discriminator (snake_case, kebab-case,
24016        // UpperCamelCase, empty) that the apiserver-side CRD schema
24017        // validator would reject far from the rebrand commit's source.
24018        // Peer to `cilium_key_endpoint_selector_carries_lower_camel_\
24019        // case_shape` / `cilium_key_to_ports_carries_lower_camel_case_\
24020        // shape` on the sibling per-CNP-body-axis grammar-pin set — the
24021        // lowerCamelCase K8s field-name grammar governs every nested
24022        // schema-field axis (including this per-CNP traffic-direction-
24023        // axis key), same convention.
24024        let v = CILIUM_KEY_INGRESS;
24025        assert!(
24026            !v.is_empty(),
24027            "CILIUM_KEY_INGRESS {v:?} must be non-empty per the K8s API \
24028             lowerCamelCase field-name grammar"
24029        );
24030        let first = v.chars().next().expect("non-empty");
24031        assert!(
24032            first.is_ascii_lowercase(),
24033            "CILIUM_KEY_INGRESS {v:?} first byte {first:?} must be \
24034             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24035             grammar (field names are always lowerCamelCase)"
24036        );
24037        assert!(
24038            v.chars().all(|c| c.is_ascii_alphanumeric()),
24039            "CILIUM_KEY_INGRESS {v:?} must be ASCII-alphanumeric \
24040             throughout per the K8s API field-name grammar — no \
24041             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24042             OpenAPI schema validator would reject"
24043        );
24044    }
24045
24046    #[test]
24047    fn cilium_key_from_endpoints_pins_canonical_value() {
24048        // Pin the actual string so a typo in this lift can't silently
24049        // rebrand the Cilium CNP `spec.ingress[].fromEndpoints[]`
24050        // identity-source selector-list-axis key the rendered CNP
24051        // document mounts its permitted-source `LabelSelector` list
24052        // under. The string is part of the cluster-side contract with
24053        // the upstream Cilium operator — the Cilium-operator-side per-
24054        // CNP identity-resolution pass keys off this axis to bind the
24055        // emitted ingress rule against the admitted source workload
24056        // identities via the K8s LabelSelector schema; a drifted value
24057        // (`"fromendpoints"` / `"fromEndPoint"` / `"sourceEndpoints"`)
24058        // at either the production emitter or a downstream renderer's
24059        // per-ingress-rule identity-source upsert silently emits a CNP
24060        // whose per-ingress-rule identity-source axis the Cilium CRD
24061        // schema validator drops as unknown, and the ingress rule
24062        // admits no source pods — every intra-mesh `:contratos` flow
24063        // the affected CNP was authored to allow drops at the eBPF
24064        // data-plane's default-deny gate. Changing this value is a
24065        // coordinated Cilium-CRD promotion alongside the upstream
24066        // Cilium project's CRD schema-migration cycle, not an
24067        // incidental edit. Peer to
24068        // `cilium_key_endpoint_selector_pins_canonical_value` (the
24069        // destination-identity axis-key pin the identity-source axis
24070        // structurally pairs with under the SPIFFE-identity-bound per-
24071        // CNP access-control contract) on the sibling per-CNP identity-
24072        // pair pin set — completes the per-CNP identity-pair
24073        // `(endpointSelector, fromEndpoints)` pin set the M3 Aplicacao
24074        // mesh renderer's eBPF data-plane contract rests on.
24075        assert_eq!(CILIUM_KEY_FROM_ENDPOINTS, "fromEndpoints");
24076    }
24077
24078    #[test]
24079    fn cilium_key_from_endpoints_carries_lower_camel_case_shape() {
24080        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24081        // lowerCamelCase identifier per the K8s API conventions
24082        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24083        // "Field names should be lowercase camelCase") — first byte
24084        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24085        // kebab-case or whitespace. Pinning the shape here means a
24086        // future rebrand on the canonical lift can't silently land a
24087        // malformed field-name discriminator (snake_case, kebab-case,
24088        // UpperCamelCase, empty) that the apiserver-side CRD schema
24089        // validator would reject far from the rebrand commit's source.
24090        // Peer to `cilium_key_endpoint_selector_carries_lower_camel_\
24091        // case_shape` / `cilium_key_ingress_carries_lower_camel_case_\
24092        // shape` / `cilium_key_to_ports_carries_lower_camel_case_shape`
24093        // on the sibling per-CNP-body-axis grammar-pin set — the
24094        // lowerCamelCase K8s field-name grammar governs every nested
24095        // schema-field axis (including this per-ingress-rule identity-
24096        // source-axis key), same convention.
24097        let v = CILIUM_KEY_FROM_ENDPOINTS;
24098        assert!(
24099            !v.is_empty(),
24100            "CILIUM_KEY_FROM_ENDPOINTS {v:?} must be non-empty per the K8s API \
24101             lowerCamelCase field-name grammar"
24102        );
24103        let first = v.chars().next().expect("non-empty");
24104        assert!(
24105            first.is_ascii_lowercase(),
24106            "CILIUM_KEY_FROM_ENDPOINTS {v:?} first byte {first:?} must be \
24107             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24108             grammar (field names are always lowerCamelCase)"
24109        );
24110        assert!(
24111            v.chars().all(|c| c.is_ascii_alphanumeric()),
24112            "CILIUM_KEY_FROM_ENDPOINTS {v:?} must be ASCII-alphanumeric \
24113             throughout per the K8s API field-name grammar — no \
24114             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24115             OpenAPI schema validator would reject"
24116        );
24117    }
24118
24119    #[test]
24120    fn cilium_key_ports_pins_canonical_value() {
24121        // Pin the actual string so a typo in this lift can't silently
24122        // rebrand the Cilium CNP `spec.ingress[].toPorts[].ports[]`
24123        // per-`toPorts[]`-entry L4-port-tuple-list-container-axis key
24124        // the rendered CNP document mounts its per-port-set
24125        // `[{port, protocol}]` list under. The string is part of the
24126        // cluster-side contract with the upstream Cilium operator —
24127        // the Cilium-operator-side per-CNP L4-allow eBPF-program-
24128        // generation pass keys off this axis to source the per-port-set
24129        // `(port, protocol)` tuples the emitted ingress rule admits; a
24130        // drifted value (`"port"` / `"portList"` / `"L4Ports"`) at
24131        // either the production emitter or a downstream renderer's
24132        // per-`toPorts[]`-entry L4-port-tuple-list upsert silently
24133        // emits a per-`toPorts[]` entry whose L4-port-tuple-list-
24134        // container axis the Cilium CRD schema validator drops as
24135        // unknown, and the port-set admits no `(port, protocol)`
24136        // tuple — every intra-mesh `:contratos` flow the affected CNP
24137        // was authored to allow drops at the eBPF data-plane's
24138        // default-deny gate. Changing this value is a coordinated
24139        // Cilium-CRD promotion alongside the upstream Cilium project's
24140        // CRD schema-migration cycle, not an incidental edit. Peer to
24141        // `cilium_key_to_ports_pins_canonical_value` (the outer per-
24142        // ingress-rule port-set-container axis-key pin the L4 port-
24143        // tuple-list-container axis nests inside) on the sibling per-
24144        // CNP-dispatch-axis pin set — completes the per-CNP L4-half
24145        // `(toPorts, ports)` container-pair pin the M3 Aplicacao mesh
24146        // renderer's eBPF data-plane L4-allow contract rests on.
24147        assert_eq!(CILIUM_KEY_PORTS, "ports");
24148    }
24149
24150    #[test]
24151    fn cilium_key_ports_carries_lower_camel_case_shape() {
24152        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24153        // lowerCamelCase identifier per the K8s API conventions
24154        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24155        // "Field names should be lowercase camelCase") — first byte
24156        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24157        // kebab-case or whitespace. Pinning the shape here means a
24158        // future rebrand on the canonical lift can't silently land a
24159        // malformed field-name discriminator (snake_case, kebab-case,
24160        // UpperCamelCase, empty) that the apiserver-side CRD schema
24161        // validator would reject far from the rebrand commit's source.
24162        // Peer to `cilium_key_endpoint_selector_carries_lower_camel_\
24163        // case_shape` / `cilium_key_ingress_carries_lower_camel_case_\
24164        // shape` / `cilium_key_to_ports_carries_lower_camel_case_shape`
24165        // / `cilium_key_from_endpoints_carries_lower_camel_case_shape`
24166        // on the sibling per-CNP-body-axis grammar-pin set — the
24167        // lowerCamelCase K8s field-name grammar governs every nested
24168        // schema-field axis (including this per-`toPorts[]`-entry L4-
24169        // port-tuple-list-container-axis key), same convention.
24170        let v = CILIUM_KEY_PORTS;
24171        assert!(
24172            !v.is_empty(),
24173            "CILIUM_KEY_PORTS {v:?} must be non-empty per the K8s API \
24174             lowerCamelCase field-name grammar"
24175        );
24176        let first = v.chars().next().expect("non-empty");
24177        assert!(
24178            first.is_ascii_lowercase(),
24179            "CILIUM_KEY_PORTS {v:?} first byte {first:?} must be \
24180             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24181             grammar (field names are always lowerCamelCase)"
24182        );
24183        assert!(
24184            v.chars().all(|c| c.is_ascii_alphanumeric()),
24185            "CILIUM_KEY_PORTS {v:?} must be ASCII-alphanumeric \
24186             throughout per the K8s API field-name grammar — no \
24187             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24188             OpenAPI schema validator would reject"
24189        );
24190    }
24191
24192    #[test]
24193    fn cilium_key_authentication_pins_canonical_value() {
24194        // Pin the actual string so a typo in this lift can't silently
24195        // rebrand the Cilium CNP `spec.ingress[].authentication`
24196        // per-ingress-rule mutual-auth-policy body-axis key the
24197        // rendered CNP document mounts its per-rule mTLS enforcement
24198        // block under. The string is part of the cluster-side
24199        // contract with the upstream Cilium operator — the Cilium-
24200        // operator-side per-CNP mutual-auth SPIFFE-handshake pipeline
24201        // keys off this axis to source the per-rule mTLS enforcement
24202        // mode (`required` vs `disabled`); a drifted value (`"auth"`
24203        // / `"mutualAuth"` / `"mtls"` / `"authPolicy"`) at either
24204        // the production emitter or a downstream renderer's per-
24205        // ingress-rule mutual-auth upsert silently emits a per-
24206        // `ingress[]` entry whose mutual-auth-axis the Cilium CRD
24207        // schema validator drops as unknown, and the ingress rule
24208        // falls back to the cluster-default authentication mode
24209        // (typically `"disabled"` — no mutual-auth enforcement)
24210        // silently bypassing the SPIFFE-identity-bound mTLS handshake
24211        // every intra-mesh `:contratos` flow the CNP was authored to
24212        // protect. Changing this value is a coordinated Cilium-CRD
24213        // promotion alongside the upstream Cilium project's CRD
24214        // schema-migration cycle, not an incidental edit. Peer to
24215        // `cilium_key_from_endpoints_pins_canonical_value` /
24216        // `cilium_key_to_ports_pins_canonical_value` (the sibling
24217        // per-ingress-rule-body-axis pins the mutual-auth axis pairs
24218        // with at the per-rule triple
24219        // `(fromEndpoints, toPorts, authentication)`) on the sibling
24220        // per-CNP-dispatch-axis pin set — completes the per-CNP per-
24221        // ingress-rule-body triple the M3 Aplicacao mesh renderer's
24222        // SPIFFE-identity-bound per-edge mTLS contract rests on.
24223        assert_eq!(CILIUM_KEY_AUTHENTICATION, "authentication");
24224    }
24225
24226    #[test]
24227    fn cilium_key_authentication_carries_lower_camel_case_shape() {
24228        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24229        // lowerCamelCase identifier per the K8s API conventions
24230        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24231        // "Field names should be lowercase camelCase") — first byte
24232        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24233        // kebab-case or whitespace. Pinning the shape here means a
24234        // future rebrand on the canonical lift can't silently land a
24235        // malformed field-name discriminator (snake_case, kebab-case,
24236        // UpperCamelCase, empty) that the apiserver-side CRD schema
24237        // validator would reject far from the rebrand commit's source.
24238        // Peer to `cilium_key_endpoint_selector_carries_lower_camel_\
24239        // case_shape` / `cilium_key_ingress_carries_lower_camel_case_\
24240        // shape` / `cilium_key_to_ports_carries_lower_camel_case_shape`
24241        // / `cilium_key_from_endpoints_carries_lower_camel_case_shape`
24242        // / `cilium_key_ports_carries_lower_camel_case_shape` on the
24243        // sibling per-CNP-body-axis grammar-pin set — the
24244        // lowerCamelCase K8s field-name grammar governs every nested
24245        // schema-field axis (including this per-`ingress[]`-entry
24246        // mutual-auth-policy body-axis key), same convention.
24247        let v = CILIUM_KEY_AUTHENTICATION;
24248        assert!(
24249            !v.is_empty(),
24250            "CILIUM_KEY_AUTHENTICATION {v:?} must be non-empty per the K8s API \
24251             lowerCamelCase field-name grammar"
24252        );
24253        let first = v.chars().next().expect("non-empty");
24254        assert!(
24255            first.is_ascii_lowercase(),
24256            "CILIUM_KEY_AUTHENTICATION {v:?} first byte {first:?} must be \
24257             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24258             grammar (field names are always lowerCamelCase)"
24259        );
24260        assert!(
24261            v.chars().all(|c| c.is_ascii_alphanumeric()),
24262            "CILIUM_KEY_AUTHENTICATION {v:?} must be ASCII-alphanumeric \
24263             throughout per the K8s API field-name grammar — no \
24264             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24265             OpenAPI schema validator would reject"
24266        );
24267    }
24268
24269    #[test]
24270    fn cilium_key_mode_pins_canonical_value() {
24271        // Pin the actual string so a typo in this lift can't silently
24272        // rebrand the Cilium CNP `spec.ingress[].authentication.mode`
24273        // per-ingress-rule mutual-auth-mode-discriminator leaf-scalar-
24274        // axis key the rendered CNP document mounts its per-rule mTLS
24275        // enforcement mode value under. The string is part of the
24276        // cluster-side contract with the upstream Cilium operator —
24277        // the Cilium-operator-side per-CNP mutual-auth SPIFFE-handshake
24278        // pipeline reads this leaf axis to source the per-rule mTLS
24279        // enforcement mode value (`"required"` vs `"disabled"`); a
24280        // drifted key (`"policy"` / `"authMode"` / `"handshakeMode"`)
24281        // at either the production emitter or a downstream renderer's
24282        // per-ingress-rule mutual-auth-mode-leaf upsert silently emits
24283        // a per-`ingress[]` entry whose mutual-auth block's mode-
24284        // discriminator leaf-axis the Cilium CRD schema validator
24285        // drops as unknown, and the ingress rule falls back to the
24286        // cluster-default authentication mode (typically `"disabled"`
24287        // — no mutual-auth enforcement) silently bypassing the SPIFFE-
24288        // identity-bound mTLS handshake every intra-mesh `:contratos`
24289        // flow the CNP was authored to protect. Changing this value is
24290        // a coordinated Cilium-CRD promotion alongside the upstream
24291        // Cilium project's CRD schema-migration cycle, not an
24292        // incidental edit. Peer to
24293        // `cilium_key_authentication_pins_canonical_value` on the
24294        // sibling per-ingress-rule mutual-auth body-axis pin set —
24295        // completes the per-rule mutual-auth
24296        // `(authentication → mode)` body/leaf axis pin pair the M3
24297        // Aplicacao mesh renderer's SPIFFE-identity-bound per-edge
24298        // mTLS enforcement contract rests on. Byte-identical to the
24299        // sibling `:politicas :circuit-breaker (:window)` /
24300        // `:placement :estrategia` overlay mode-like axes today, but
24301        // semantically distinct: this const names the Cilium CRD's
24302        // per-authentication-block mode-discriminator leaf-axis key
24303        // (spelled per the Cilium project's CRD schema), so a future
24304        // rebrand on the Cilium CRD's per-authentication-block mode-
24305        // leaf axis lands at its own canonical const without coupling
24306        // the Cilium schema to any peer surface that happens to carry
24307        // the same byte.
24308        assert_eq!(CILIUM_KEY_MODE, "mode");
24309    }
24310
24311    #[test]
24312    fn cilium_key_mode_carries_lower_camel_case_shape() {
24313        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24314        // lowerCamelCase identifier per the K8s API conventions
24315        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24316        // "Field names should be lowercase camelCase") — first byte
24317        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24318        // kebab-case or whitespace. Pinning the shape here means a
24319        // future rebrand on the canonical lift can't silently land a
24320        // malformed field-name discriminator (snake_case, kebab-case,
24321        // UpperCamelCase, empty) that the apiserver-side CRD schema
24322        // validator would reject far from the rebrand commit's source.
24323        // Peer to `cilium_key_authentication_carries_lower_camel_case_\
24324        // shape` on the sibling per-ingress-rule mutual-auth-body-axis
24325        // grammar-pin — the lowerCamelCase K8s field-name grammar
24326        // governs every nested schema-field axis (including this
24327        // per-authentication-block mode-discriminator leaf-axis key),
24328        // same convention.
24329        let v = CILIUM_KEY_MODE;
24330        assert!(
24331            !v.is_empty(),
24332            "CILIUM_KEY_MODE {v:?} must be non-empty per the K8s API \
24333             lowerCamelCase field-name grammar"
24334        );
24335        let first = v.chars().next().expect("non-empty");
24336        assert!(
24337            first.is_ascii_lowercase(),
24338            "CILIUM_KEY_MODE {v:?} first byte {first:?} must be \
24339             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24340             grammar (field names are always lowerCamelCase)"
24341        );
24342        assert!(
24343            v.chars().all(|c| c.is_ascii_alphanumeric()),
24344            "CILIUM_KEY_MODE {v:?} must be ASCII-alphanumeric \
24345             throughout per the K8s API field-name grammar — no \
24346             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24347             OpenAPI schema validator would reject"
24348        );
24349    }
24350
24351    #[test]
24352    fn cilium_key_http_pins_canonical_value() {
24353        // Pin the actual string so a typo in this lift can't silently
24354        // rebrand the Cilium CNP `spec.ingress[].toPorts[].rules.http`
24355        // per-`toPorts[]` L7-HTTP-rule-list-discriminator container-axis
24356        // key the rendered CNP document mounts its per-`toPorts[]` L7
24357        // URL-path-prefix predicate list under. The string is part of the
24358        // cluster-side contract with the upstream Cilium operator — the
24359        // Cilium-operator-side per-CNP L7 dispatch pipeline reads this
24360        // container axis to source the per-`toPorts[]` L7 URL-path-prefix
24361        // predicate list the ingress rule was authored to filter each
24362        // HTTP-shaped `:contratos` flow through; a drifted key (`"HTTP"` /
24363        // `"Http"` / `"httpRules"` / `"httpMatch"`) at either the
24364        // production emitter or a downstream renderer's per-`toPorts[]`
24365        // L7-rule-list-discriminator upsert silently emits a per-
24366        // `toPorts[]` entry whose L7-HTTP-rule-list-discriminator key the
24367        // Cilium CRD schema validator drops as unknown, and the per-
24368        // `toPorts[]` entry falls back to L4-only enforcement — no L7
24369        // URL-path predicate is applied — silently admitting every HTTP-
24370        // method / URL-path combination the ingress rule was authored to
24371        // filter to the exact path prefix set the typed `:contratos`
24372        // graph names at the L7 introspection axis. Changing this value
24373        // is a coordinated Cilium-CRD promotion alongside the upstream
24374        // Cilium project's CRD schema-migration cycle, not an incidental
24375        // edit. Peer to `cilium_key_mode_pins_canonical_value` /
24376        // `cilium_key_authentication_pins_canonical_value` on the
24377        // sibling per-ingress-rule mutual-auth body/leaf axis pin pair —
24378        // completes the per-`toPorts[]` L7-introspection
24379        // `(rules → http)` container/protocol-discriminator axis pin
24380        // pair the M3 Aplicacao mesh renderer's HTTP-shaped-`:contratos`
24381        // URL-path-prefix-filtering L7-enforcement contract rests on.
24382        // Byte-identical to the sibling `Gateway.spec.listeners[].name`
24383        // arbitrary-author-chosen listener-name today (`"http"` — the
24384        // author-chosen name for the substrate's V0 HTTP listener), but
24385        // semantically distinct: this const names the Cilium CRD's per-
24386        // `toPorts[]` L7-HTTP-rule-list-discriminator container-axis key
24387        // (spelled per the Cilium project's CRD schema), so a future
24388        // rebrand on the Cilium CRD's L7-HTTP-rule-list-discriminator
24389        // axis lands at its own canonical const without coupling the
24390        // Cilium schema to any peer surface that happens to carry the
24391        // same byte.
24392        assert_eq!(CILIUM_KEY_HTTP, "http");
24393    }
24394
24395    #[test]
24396    fn cilium_key_http_carries_lower_camel_case_shape() {
24397        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24398        // lowerCamelCase identifier per the K8s API conventions
24399        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24400        // "Field names should be lowercase camelCase") — first byte
24401        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24402        // kebab-case or whitespace. Pinning the shape here means a
24403        // future rebrand on the canonical lift can't silently land a
24404        // malformed field-name discriminator (snake_case, kebab-case,
24405        // UpperCamelCase, empty) that the apiserver-side CRD schema
24406        // validator would reject far from the rebrand commit's source.
24407        // Peer to `cilium_key_mode_carries_lower_camel_case_shape` /
24408        // `cilium_key_authentication_carries_lower_camel_case_shape` on
24409        // the sibling per-ingress-rule mutual-auth-body/leaf-axis
24410        // grammar-pin set — the lowerCamelCase K8s field-name grammar
24411        // governs every nested schema-field axis (including this per-
24412        // `toPorts[]` L7-HTTP-rule-list-discriminator container-axis
24413        // key), same convention.
24414        let v = CILIUM_KEY_HTTP;
24415        assert!(
24416            !v.is_empty(),
24417            "CILIUM_KEY_HTTP {v:?} must be non-empty per the K8s API \
24418             lowerCamelCase field-name grammar"
24419        );
24420        let first = v.chars().next().expect("non-empty");
24421        assert!(
24422            first.is_ascii_lowercase(),
24423            "CILIUM_KEY_HTTP {v:?} first byte {first:?} must be \
24424             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24425             grammar (field names are always lowerCamelCase)"
24426        );
24427        assert!(
24428            v.chars().all(|c| c.is_ascii_alphanumeric()),
24429            "CILIUM_KEY_HTTP {v:?} must be ASCII-alphanumeric \
24430             throughout per the K8s API field-name grammar — no \
24431             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24432             OpenAPI schema validator would reject"
24433        );
24434    }
24435
24436    #[test]
24437    fn kube_key_type_pins_canonical_value() {
24438        // Pin the actual string so a typo in this lift can't silently
24439        // rebrand the K8s discriminated-union `type` scalar-discriminator
24440        // container-axis key every rendered CR mounts its per-position
24441        // discriminated-union type-value under. The string is part of the
24442        // cluster-side contract with every K8s apiserver-side OpenAPI
24443        // schema validator — the Gateway API v1 gateway-class-controller's
24444        // per-`HTTPRouteMatch` path-selection-predicate dispatch pass
24445        // reads this scalar-key to source the path-match-strategy
24446        // discriminator (the closed `PathMatchType` OpenAPI schema enum's
24447        // `{Exact, PathPrefix, RegularExpression}` set) the per-rule L7
24448        // URL-path-filtering was authored to bind — a drifted key
24449        // (`"Type"` / `"kind"` / `"discriminator"` / `"predicate"`) at
24450        // either the production emitter or a downstream renderer's per-
24451        // `HTTPRouteMatch` path-selection-predicate discriminator upsert
24452        // silently emits a per-match entry whose discriminator scalar-key
24453        // the Gateway API v1 `HTTPPathMatch` OpenAPI schema validator
24454        // drops as unknown, and the per-match entry falls back to the
24455        // schema-side default path-match-strategy — silently admitting
24456        // every URL-path prefix the ingress rule was authored to filter
24457        // to the exact predicate the typed `:entrada :paths` slot names
24458        // at the request-path-selection axis. Changing this value is a
24459        // coordinated K8s-API-conventions promotion alongside the
24460        // upstream sig-architecture per-version deprecation cycle, not
24461        // an incidental edit. Peer to
24462        // `cilium_key_http_pins_canonical_value` /
24463        // `cilium_key_mode_pins_canonical_value` /
24464        // `cilium_key_authentication_pins_canonical_value` on the
24465        // sibling per-CRD-body-axis pin set — extends the canonical-
24466        // string-pin discipline from the per-CRD-body-axis surfaces
24467        // onto the load-bearing nested K8s-discriminated-union-type-
24468        // scalar-discriminator axis every downstream apiserver-side
24469        // OpenAPI-schema-validator / gateway-class-controller consumer
24470        // of the rendered mesh bundle keys off before it can commit to
24471        // a per-match request-path-selection predicate.
24472        assert_eq!(KUBE_KEY_TYPE, "type");
24473    }
24474
24475    #[test]
24476    fn kube_key_type_carries_lower_camel_case_shape() {
24477        // Cross-axis invariant: a Kubernetes CRD schema field name is a
24478        // lowerCamelCase identifier per the K8s API conventions
24479        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
24480        // "Field names should be lowercase camelCase") — first byte
24481        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
24482        // kebab-case or whitespace. Pinning the shape here means a
24483        // future rebrand on the canonical lift can't silently land a
24484        // malformed field-name discriminator (snake_case, kebab-case,
24485        // UpperCamelCase, empty) that the apiserver-side CRD schema
24486        // validator would reject far from the rebrand commit's source.
24487        // Peer to `cilium_key_http_carries_lower_camel_case_shape` /
24488        // `cilium_key_mode_carries_lower_camel_case_shape` /
24489        // `cilium_key_authentication_carries_lower_camel_case_shape` on
24490        // the sibling per-CRD-body-axis grammar-pin set — the
24491        // lowerCamelCase K8s field-name grammar governs every nested
24492        // schema-field axis (including this K8s-discriminated-union-
24493        // type-scalar-discriminator axis), same convention.
24494        let v = KUBE_KEY_TYPE;
24495        assert!(
24496            !v.is_empty(),
24497            "KUBE_KEY_TYPE {v:?} must be non-empty per the K8s API \
24498             lowerCamelCase field-name grammar"
24499        );
24500        let first = v.chars().next().expect("non-empty");
24501        assert!(
24502            first.is_ascii_lowercase(),
24503            "KUBE_KEY_TYPE {v:?} first byte {first:?} must be \
24504             ASCII-lowercase per the K8s API lowerCamelCase field-name \
24505             grammar (field names are always lowerCamelCase)"
24506        );
24507        assert!(
24508            v.chars().all(|c| c.is_ascii_alphanumeric()),
24509            "KUBE_KEY_TYPE {v:?} must be ASCII-alphanumeric \
24510             throughout per the K8s API field-name grammar — no \
24511             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24512             OpenAPI schema validator would reject"
24513        );
24514    }
24515
24516    #[test]
24517    fn gateway_api_kind_gateway_pins_canonical_value() {
24518        // Pin the actual string so a typo in this lift can't silently
24519        // rebrand the Gateway-API-conformant `Gateway` CRD `kind`
24520        // discriminator the rendered Gateway document's top-level
24521        // `kind` axis declares. The string is part of the cluster-side
24522        // contract with every Gateway-API-conformant gateway
24523        // implementation (Cilium, Istio, Envoy Gateway, NGINX) — the
24524        // apiserver-side CRD resolution contract is the
24525        // `(apiVersion, kind)` tuple keyed against the registered
24526        // `CustomResourceDefinition`, so the kind half of the tuple is
24527        // exactly as load-bearing as the sibling
24528        // [`GATEWAY_API_API_VERSION`] apiVersion half. A drifted value
24529        // (e.g. an upstream Gateway-API rebrand to `GatewayV1`) lands
24530        // the rendered document outside the apiserver-side CRD
24531        // registration; changing it is a coordinated Gateway-API
24532        // promotion alongside the upstream SIG-Network deprecation
24533        // cycle, not an incidental edit. Peer to
24534        // `cilium_kind_network_policy_pins_canonical_value` /
24535        // `flux_kind_kustomization_pins_canonical_value` /
24536        // `flux_kind_helm_release_pins_canonical_value` /
24537        // `flux_kind_git_repository_pins_canonical_value` on the
24538        // sibling cluster-side-CRD-`kind`-discriminator pin set —
24539        // extends the canonical-string-pin discipline from the
24540        // Cilium-CRD + Flux v2 controller-triplet `kind`-axis surfaces
24541        // onto the Gateway-API-CRD `kind`-axis surface, beginning the
24542        // per-Gateway-API-CRD kind+apiVersion canonical-pin pair the
24543        // M3 Aplicacao mesh renderer's external `:entrada` ingress
24544        // contract rests on.
24545        assert_eq!(GATEWAY_API_KIND_GATEWAY, "Gateway");
24546    }
24547
24548    #[test]
24549    fn gateway_api_kind_gateway_carries_upper_camel_case_shape() {
24550        // Cross-axis invariant: a Kubernetes CRD `kind` discriminator is
24551        // an UpperCamelCase identifier per the K8s API conventions
24552        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds —
24553        // "Kinds are always UpperCamelCase"). Pinning the shape here
24554        // means a future rebrand on the canonical lift can't silently
24555        // land a malformed kind discriminator (snake_case, kebab-case,
24556        // lowercase, empty) that every downstream YAML-aware
24557        // deserializer would reject far from the rebrand commit's
24558        // source. The first-byte uppercase / rest-ASCII-alphanumeric
24559        // invariant is the load-bearing K8s API typed-discovery
24560        // contract: a value the apiserver's `RESTMapper` consults to
24561        // resolve the CRD's `RESTKind`. Peer to
24562        // `cilium_kind_network_policy_carries_upper_camel_case_shape` /
24563        // `flux_kind_kustomization_carries_upper_camel_case_shape` /
24564        // `flux_kind_helm_release_carries_upper_camel_case_shape` /
24565        // `flux_kind_git_repository_carries_upper_camel_case_shape` on
24566        // the sibling cluster-side-CRD-`kind`-discriminator surface.
24567        let v = GATEWAY_API_KIND_GATEWAY;
24568        assert!(
24569            !v.is_empty(),
24570            "GATEWAY_API_KIND_GATEWAY {v:?} must be non-empty per the K8s API \
24571             UpperCamelCase kind discriminator grammar"
24572        );
24573        let first = v.chars().next().expect("non-empty");
24574        assert!(
24575            first.is_ascii_uppercase(),
24576            "GATEWAY_API_KIND_GATEWAY {v:?} first byte {first:?} must be \
24577             ASCII-uppercase per the K8s API UpperCamelCase kind discriminator \
24578             grammar (Kinds are always UpperCamelCase)"
24579        );
24580        assert!(
24581            v.chars().all(|c| c.is_ascii_alphanumeric()),
24582            "GATEWAY_API_KIND_GATEWAY {v:?} must be ASCII-alphanumeric \
24583             throughout per the K8s API kind discriminator grammar — no \
24584             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24585             RESTMapper would reject"
24586        );
24587    }
24588
24589    #[test]
24590    fn gateway_api_kind_http_route_pins_canonical_value() {
24591        // Pin the actual string so a typo in this lift can't silently
24592        // rebrand the Gateway-API-conformant `HTTPRoute` CRD `kind`
24593        // discriminator the rendered HTTPRoute document's top-level
24594        // `kind` axis declares. The string is part of the cluster-side
24595        // contract with every Gateway-API-conformant gateway
24596        // implementation (Cilium, Istio, Envoy Gateway, NGINX) — the
24597        // apiserver-side CRD resolution contract is the
24598        // `(apiVersion, kind)` tuple keyed against the registered
24599        // `CustomResourceDefinition`, so the kind half of the tuple is
24600        // exactly as load-bearing as the sibling
24601        // [`GATEWAY_API_API_VERSION`] apiVersion half. A drifted value
24602        // (e.g. an upstream Gateway-API rebrand to `HTTPRouteV1`) lands
24603        // the rendered document outside the apiserver-side CRD
24604        // registration; changing it is a coordinated Gateway-API
24605        // promotion alongside the upstream SIG-Network deprecation
24606        // cycle, not an incidental edit. Peer to
24607        // `gateway_api_kind_gateway_pins_canonical_value` /
24608        // `cilium_kind_network_policy_pins_canonical_value` /
24609        // `flux_kind_kustomization_pins_canonical_value` /
24610        // `flux_kind_helm_release_pins_canonical_value` /
24611        // `flux_kind_git_repository_pins_canonical_value` on the
24612        // sibling cluster-side-CRD-`kind`-discriminator pin set —
24613        // completes the per-Gateway-API-CRD `kind`-axis canonical-pin
24614        // pair across the `(Gateway, HTTPRoute)` pair the renderer's
24615        // `gateway_routes` external `:entrada` ingress contract emits
24616        // together.
24617        assert_eq!(GATEWAY_API_KIND_HTTP_ROUTE, "HTTPRoute");
24618    }
24619
24620    #[test]
24621    fn gateway_api_kind_http_route_carries_upper_camel_case_shape() {
24622        // Cross-axis invariant: a Kubernetes CRD `kind` discriminator is
24623        // an UpperCamelCase identifier per the K8s API conventions
24624        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds —
24625        // "Kinds are always UpperCamelCase"). Acronyms like HTTP stay
24626        // ASCII-uppercase across the prefix per the same convention
24627        // (the K8s API Kinds for `HTTPRoute`, `TCPRoute`, `TLSRoute`,
24628        // `GRPCRoute` carry the full-uppercase protocol acronym).
24629        // Pinning the shape here means a future rebrand on the
24630        // canonical lift can't silently land a malformed kind
24631        // discriminator (snake_case, kebab-case, lowercase, empty)
24632        // that every downstream YAML-aware deserializer would reject
24633        // far from the rebrand commit's source. The first-byte
24634        // uppercase / rest-ASCII-alphanumeric invariant is the
24635        // load-bearing K8s API typed-discovery contract: a value the
24636        // apiserver's `RESTMapper` consults to resolve the CRD's
24637        // `RESTKind`. Peer to
24638        // `gateway_api_kind_gateway_carries_upper_camel_case_shape` /
24639        // `cilium_kind_network_policy_carries_upper_camel_case_shape` /
24640        // `flux_kind_kustomization_carries_upper_camel_case_shape` /
24641        // `flux_kind_helm_release_carries_upper_camel_case_shape` /
24642        // `flux_kind_git_repository_carries_upper_camel_case_shape` on
24643        // the sibling cluster-side-CRD-`kind`-discriminator surface.
24644        let v = GATEWAY_API_KIND_HTTP_ROUTE;
24645        assert!(
24646            !v.is_empty(),
24647            "GATEWAY_API_KIND_HTTP_ROUTE {v:?} must be non-empty per the K8s API \
24648             UpperCamelCase kind discriminator grammar"
24649        );
24650        let first = v.chars().next().expect("non-empty");
24651        assert!(
24652            first.is_ascii_uppercase(),
24653            "GATEWAY_API_KIND_HTTP_ROUTE {v:?} first byte {first:?} must be \
24654             ASCII-uppercase per the K8s API UpperCamelCase kind discriminator \
24655             grammar (Kinds are always UpperCamelCase)"
24656        );
24657        assert!(
24658            v.chars().all(|c| c.is_ascii_alphanumeric()),
24659            "GATEWAY_API_KIND_HTTP_ROUTE {v:?} must be ASCII-alphanumeric \
24660             throughout per the K8s API kind discriminator grammar — no \
24661             snake_case, kebab-case, or whitespace bytes the apiserver-side \
24662             RESTMapper would reject"
24663        );
24664    }
24665
24666    #[test]
24667    fn gateway_api_protocol_http_pins_canonical_value() {
24668        // Pin the actual string so a typo in this lift can't silently
24669        // rebrand the Gateway API v1 `ProtocolType` OpenAPI schema enum's
24670        // canonical `HTTP` listener-protocol value the rendered
24671        // `Gateway.spec.listeners[].protocol` scalar declares. The value
24672        // is part of the cluster-side contract with every Gateway-API-
24673        // conformant gateway implementation (Cilium, Istio, Envoy
24674        // Gateway, NGINX) — the gateway-class-controller's per-listener
24675        // bind loop keys off this exact byte-sequence to select the L7
24676        // parser + TLS termination strategy; the Gateway API v1
24677        // `ProtocolType` OpenAPI schema enum admits the closed set
24678        // `{"HTTP", "HTTPS", "TCP", "TLS", "UDP"}` verbatim, so a
24679        // drifted value (`"http"` / `"Http"` / `"HTTP/1.1"` / `"http/1.1"`)
24680        // lands the rendered `Gateway` outside the `ProtocolType` enum's
24681        // admitted set and every external `:entrada` HTTP flow drops at
24682        // the gateway-class-controller's admission gate. Changing this
24683        // value is a coordinated Gateway API `ProtocolType` promotion
24684        // alongside the upstream SIG-Network deprecation cycle, not an
24685        // incidental edit. Peer to
24686        // `gateway_api_kind_gateway_pins_canonical_value` /
24687        // `gateway_api_kind_http_route_pins_canonical_value` /
24688        // `default_gateway_class_name_pins_canonical_value` on the
24689        // sibling Gateway-API-CRD-`kind`-discriminator + Gateway-
24690        // controller-binding-scalar-value pin set — extends the pair
24691        // of `kind`-axis canonical-value pins across the
24692        // `(Gateway, HTTPRoute)` pair onto the sibling per-Gateway
24693        // `spec.listeners[].protocol` listener-protocol-scalar-value axis
24694        // the same `gateway_routes` external `:entrada` ingress emitter
24695        // carries.
24696        assert_eq!(GATEWAY_API_PROTOCOL_HTTP, "HTTP");
24697    }
24698
24699    #[test]
24700    fn gateway_api_protocol_http_carries_upper_case_shape() {
24701        // Cross-axis invariant: the Gateway API v1 `ProtocolType` OpenAPI
24702        // schema enum admits the closed set
24703        // `{"HTTP", "HTTPS", "TCP", "TLS", "UDP"}` — every admitted value
24704        // is ASCII-uppercase throughout per the upstream SIG-Network
24705        // Gateway API convention (see
24706        // https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.ProtocolType
24707        // — the admitted values are the transport / application-layer
24708        // protocol acronyms in their canonical uppercase form). Pinning
24709        // the shape here means a future rebrand on the canonical lift
24710        // can't silently land a malformed listener-protocol scalar
24711        // (lowercase `"http"`, mixed-case `"Http"`, dotted `"HTTP/1.1"`,
24712        // empty) that the K8s Gateway API v1 `ProtocolType` OpenAPI
24713        // schema enum would reject at admission time far from the
24714        // rebrand commit's source. The all-ASCII-uppercase invariant is
24715        // the load-bearing Gateway-API-implementation-side typed
24716        // listener-parser-selection contract: a value the gateway-
24717        // class-controller's per-listener bind loop selects the L7
24718        // parser + TLS termination strategy from.
24719        let v = GATEWAY_API_PROTOCOL_HTTP;
24720        assert!(
24721            !v.is_empty(),
24722            "GATEWAY_API_PROTOCOL_HTTP {v:?} must be non-empty per the \
24723             Gateway API v1 `ProtocolType` OpenAPI schema enum grammar"
24724        );
24725        assert!(
24726            v.chars().all(|c| c.is_ascii_uppercase()),
24727            "GATEWAY_API_PROTOCOL_HTTP {v:?} must be ASCII-uppercase \
24728             throughout per the Gateway API v1 `ProtocolType` OpenAPI \
24729             schema enum convention — no lowercase, mixed-case, dotted, \
24730             or whitespace bytes the gateway-class-controller's per-\
24731             listener bind loop would reject"
24732        );
24733    }
24734
24735    #[test]
24736    fn gateway_api_path_match_type_path_prefix_pins_canonical_value() {
24737        // Pin the actual string so a typo in this lift can't silently
24738        // rebrand the Gateway API v1 `PathMatchType` OpenAPI schema
24739        // enum's canonical `PathPrefix` per-`HTTPRouteMatch` path-
24740        // selection-predicate discriminator value the rendered
24741        // `HTTPRoute.spec.rules[].matches[].path.type` scalar declares.
24742        // The value is part of the cluster-side contract with every
24743        // Gateway-API-conformant gateway implementation (Cilium, Istio,
24744        // Envoy Gateway, NGINX) — the gateway-class-controller's
24745        // per-rule L7 dispatch loop keys off this exact byte-sequence
24746        // to select the request-path-selection predicate; the Gateway
24747        // API v1 `PathMatchType` OpenAPI schema enum admits the closed
24748        // set `{"Exact", "PathPrefix", "RegularExpression"}` verbatim,
24749        // so a drifted value (`"pathPrefix"` / `"path_prefix"` /
24750        // `"Prefix"` / `"path-prefix"`) lands the rendered `HTTPRoute`
24751        // outside the `PathMatchType` enum's admitted set and every
24752        // external `:entrada` path-filtered flow drops at the gateway-
24753        // class-controller's admission gate. Changing this value is a
24754        // coordinated Gateway API `PathMatchType` promotion alongside
24755        // the upstream SIG-Network deprecation cycle, not an incidental
24756        // edit. Peer to
24757        // `gateway_api_protocol_http_pins_canonical_value` /
24758        // `gateway_api_kind_gateway_pins_canonical_value` /
24759        // `gateway_api_kind_http_route_pins_canonical_value` /
24760        // `default_gateway_class_name_pins_canonical_value` on the
24761        // sibling Gateway-API-v1-OpenAPI-schema-enum-value +
24762        // Gateway-API-CRD-`kind`-discriminator + Gateway-controller-
24763        // binding-scalar-value pin set — extends the canonical-
24764        // Gateway-API-v1-OpenAPI-schema-enum-value single-sourcing
24765        // discipline the `ProtocolType.HTTP` pin established onto the
24766        // sibling `PathMatchType.PathPrefix` per-`HTTPRouteMatch`
24767        // path-selection-predicate discriminator the same
24768        // `gateway_routes` external `:entrada` ingress emitter carries
24769        // under the shared `HTTPRoute` body.
24770        assert_eq!(GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX, "PathPrefix");
24771    }
24772
24773    #[test]
24774    fn gateway_api_path_match_type_path_prefix_carries_upper_camel_case_shape() {
24775        // Cross-axis invariant: the Gateway API v1 `PathMatchType`
24776        // OpenAPI schema enum admits the closed set
24777        // `{"Exact", "PathPrefix", "RegularExpression"}` — every
24778        // admitted value is UpperCamelCase per the upstream SIG-Network
24779        // Gateway API convention (see
24780        // https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.PathMatchType
24781        // — the admitted values are the request-path-selection
24782        // predicate names in their canonical UpperCamelCase form,
24783        // matching the K8s API `Kinds are always UpperCamelCase`
24784        // convention the sibling `GATEWAY_API_KIND_*` discriminators
24785        // carry on the CRD-`kind`-axis surface). Pinning the shape
24786        // here means a future rebrand on the canonical lift can't
24787        // silently land a malformed path-match-type scalar (lowercase
24788        // `"pathprefix"`, snake_case `"path_prefix"`, kebab-case
24789        // `"path-prefix"`, empty) that the K8s Gateway API v1
24790        // `PathMatchType` OpenAPI schema enum would reject at
24791        // admission time far from the rebrand commit's source. The
24792        // first-byte uppercase / rest-ASCII-alphanumeric invariant is
24793        // the load-bearing Gateway-API-implementation-side typed
24794        // per-match request-path-selection-predicate-selection
24795        // contract: a value the gateway-class-controller's per-rule
24796        // L7 dispatch loop selects the request-path-predicate
24797        // evaluator from. Peer to
24798        // `gateway_api_kind_gateway_carries_upper_camel_case_shape` /
24799        // `gateway_api_kind_http_route_carries_upper_camel_case_shape`
24800        // on the sibling cluster-side-CRD-`kind`-discriminator
24801        // UpperCamelCase pin set — extends the canonical-K8s-API-
24802        // UpperCamelCase-typed-discriminator pin discipline the
24803        // `Kind` axis carries onto the sibling Gateway API v1
24804        // `PathMatchType` OpenAPI schema enum's per-value
24805        // UpperCamelCase surface (distinct from the sibling
24806        // Gateway API v1 `ProtocolType` OpenAPI schema enum's all-
24807        // ASCII-uppercase per-value convention the
24808        // `gateway_api_protocol_http_carries_upper_case_shape` pin
24809        // carries — the two peer Gateway-API-v1 OpenAPI schema
24810        // enum-value conventions do not collapse).
24811        let v = GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX;
24812        assert!(
24813            !v.is_empty(),
24814            "GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX {v:?} must be non-empty per \
24815             the Gateway API v1 `PathMatchType` OpenAPI schema enum grammar"
24816        );
24817        let first = v.chars().next().expect("non-empty");
24818        assert!(
24819            first.is_ascii_uppercase(),
24820            "GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX {v:?} first byte {first:?} \
24821             must be ASCII-uppercase per the Gateway API v1 `PathMatchType` \
24822             OpenAPI schema enum UpperCamelCase convention"
24823        );
24824        assert!(
24825            v.chars().all(|c| c.is_ascii_alphanumeric()),
24826            "GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX {v:?} must be ASCII-\
24827             alphanumeric throughout per the Gateway API v1 `PathMatchType` \
24828             OpenAPI schema enum UpperCamelCase convention — no snake_case, \
24829             kebab-case, or whitespace bytes the gateway-class-controller's \
24830             per-rule L7 dispatch loop would reject"
24831        );
24832    }
24833
24834    #[test]
24835    fn kube_protocol_tcp_pins_canonical_value() {
24836        // Pin the actual string so a typo in this lift can't silently
24837        // rebrand the K8s core `Protocol` OpenAPI schema enum's
24838        // canonical `TCP` L4-transport-protocol scalar value the
24839        // rendered `CiliumNetworkPolicy.spec.ingress[].toPorts[].ports[]
24840        // .protocol` scalar declares. The value is part of the cluster-
24841        // side contract with every K8s-core-`Protocol`-conformant CNI
24842        // + kube-proxy + eBPF-data-plane implementation (Cilium,
24843        // Calico, kube-proxy iptables/ipvs) — the CNI's per-CNP L4
24844        // dispatch pass keys off this exact byte-sequence to select
24845        // the per-tuple L4-transport-protocol predicate; the K8s core
24846        // `Protocol` OpenAPI schema enum admits the closed set
24847        // `{"TCP", "UDP", "SCTP"}` verbatim (see
24848        // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1/#protocol-v1-core),
24849        // so a drifted value (`"tcp"` / `"Tcp"` / `"TCP/IP"` /
24850        // `"transport-tcp"`) lands the rendered `CiliumNetworkPolicy`
24851        // outside the `Protocol` enum's admitted set and every intra-
24852        // mesh `:contratos` L4-tuple-gated flow drops at the Cilium
24853        // operator's admission gate. Changing this value is a
24854        // coordinated K8s core `Protocol` promotion alongside the
24855        // upstream SIG-Network deprecation cycle, not an incidental
24856        // edit. Peer to
24857        // `gateway_api_protocol_http_pins_canonical_value` /
24858        // `gateway_api_path_match_type_path_prefix_pins_canonical_value`
24859        // on the sibling Gateway-API-v1-OpenAPI-schema-enum-value pin
24860        // set — extends the canonical-cluster-side-OpenAPI-schema-enum-
24861        // value single-sourcing discipline the Gateway-API v1
24862        // `ProtocolType.HTTP` / `PathMatchType.PathPrefix` pins
24863        // established onto the sibling K8s-core `Protocol.TCP` per-port-
24864        // tuple L4-transport-protocol-discriminator the
24865        // `cilium_network_policies` intra-mesh L4-tuple-gating emitter
24866        // carries under the shared `CiliumNetworkPolicy` body.
24867        assert_eq!(KUBE_PROTOCOL_TCP, "TCP");
24868    }
24869
24870    #[test]
24871    fn kube_protocol_tcp_carries_upper_case_shape() {
24872        // Cross-axis invariant: the K8s core `Protocol` OpenAPI schema
24873        // enum admits the closed set `{"TCP", "UDP", "SCTP"}` — every
24874        // admitted value is ASCII-uppercase throughout per the upstream
24875        // SIG-Network convention (the admitted values are the L4-
24876        // transport-protocol acronyms in their canonical uppercase form,
24877        // matching the sibling Gateway-API v1 `ProtocolType` OpenAPI
24878        // schema enum's `{"HTTP", "HTTPS", "TCP", "TLS", "UDP"}` all-
24879        // ASCII-uppercase convention the
24880        // `gateway_api_protocol_http_carries_upper_case_shape` pin
24881        // carries on the peer per-listener L7-parser-selection scalar
24882        // axis). Pinning the shape here means a future rebrand on the
24883        // canonical lift can't silently land a malformed L4-transport-
24884        // protocol scalar (lowercase `"tcp"`, mixed-case `"Tcp"`,
24885        // dotted `"TCP/IP"`, empty) that the K8s core `Protocol`
24886        // OpenAPI schema enum would reject at admission time far from
24887        // the rebrand commit's source. The all-ASCII-uppercase
24888        // invariant is the load-bearing K8s-core-`Protocol`-enum-side
24889        // typed L4-transport-selection contract: a value the CNI's per-
24890        // CNP L4 dispatch pass selects the per-tuple L4-transport-
24891        // protocol predicate from. Peer to
24892        // `gateway_api_protocol_http_carries_upper_case_shape` on the
24893        // sibling Gateway-API v1 `ProtocolType` OpenAPI schema enum's
24894        // all-ASCII-uppercase per-value convention pin set — the two
24895        // peer canonical-cluster-side-OpenAPI-schema-enum-value
24896        // uppercase conventions collapse on the shared `TCP` transport-
24897        // protocol acronym both `Protocol` enums admit at the closed-
24898        // set intersection.
24899        let v = KUBE_PROTOCOL_TCP;
24900        assert!(
24901            !v.is_empty(),
24902            "KUBE_PROTOCOL_TCP {v:?} must be non-empty per the K8s core \
24903             `Protocol` OpenAPI schema enum grammar"
24904        );
24905        assert!(
24906            v.chars().all(|c| c.is_ascii_uppercase()),
24907            "KUBE_PROTOCOL_TCP {v:?} must be ASCII-uppercase throughout \
24908             per the K8s core `Protocol` OpenAPI schema enum convention \
24909             — no lowercase, mixed-case, dotted, or whitespace bytes the \
24910             CNI's per-CNP L4 dispatch pass would reject"
24911        );
24912    }
24913
24914    #[test]
24915    fn cilium_auth_mode_required_pins_canonical_value() {
24916        // Pin the actual string so a typo in this lift can't silently
24917        // rebrand the Cilium `CiliumNetworkPolicy` `MutualAuthenticationMode`
24918        // OpenAPI schema enum's `required` mTLS-mandatory scalar-value the
24919        // rendered CNP's `spec.ingress[].authentication.mode` leaf declares
24920        // under the `:mtls-required t` affirmative arm of the typed
24921        // `:politicas :mtls-required` tristate. The value is part of the
24922        // cluster-side contract with the Cilium-agent-side per-rule mutual-
24923        // auth-block schema validator — the agent's per-rule dispatch loop
24924        // keys off this exact byte-sequence to select the SPIFFE-identity-
24925        // handshake-mandatory enforcement policy; the Cilium CNP
24926        // `MutualAuthenticationMode` OpenAPI schema enum admits the closed
24927        // set `{"required", "disabled", "test-always-fail"}` verbatim (the
24928        // `test-always-fail` arm is a Cilium-side debugging surface, not
24929        // author-reachable), so a drifted value (`"Required"` /
24930        // `"REQUIRED"` / `"mandatory"` / `"mtls-required"`) lands the
24931        // rendered `CiliumNetworkPolicy` outside the
24932        // `MutualAuthenticationMode` enum's admitted set and every intra-
24933        // mesh `:contratos` flow the CNP was authored to protect with per-
24934        // edge SPIFFE-identity-bound mutual-auth silently bypasses the
24935        // handshake at the Cilium data-plane's default-authentication mode
24936        // (typically also "disabled" today, but environment-divergent —
24937        // take effect) with no field naming the mTLS-mandatory-scalar-value-
24938        // drift root cause. Changing this value is a coordinated Cilium
24939        // CNP `MutualAuthenticationMode` promotion alongside the Cilium
24940        // project's periodic CRD schema-migration passes, not an
24941        // incidental edit. Peer to
24942        // `gateway_api_protocol_http_pins_canonical_value` /
24943        // `gateway_api_path_match_type_path_prefix_pins_canonical_value` /
24944        // `kube_protocol_tcp_pins_canonical_value` on the sibling
24945        // canonical-cluster-side-OpenAPI-schema-enum-value pin set —
24946        // extends the canonical-cluster-side-OpenAPI-schema-enum-value
24947        // single-sourcing discipline the Gateway-API v1 `ProtocolType.HTTP`
24948        // / `PathMatchType.PathPrefix` / K8s-core `Protocol.TCP` pins
24949        // established onto the sibling Cilium-CNP-side
24950        // `MutualAuthenticationMode.required` per-rule mTLS-mandatory
24951        // scalar-value the `cilium_network_policies` per-edge SPIFFE-
24952        // identity-bound mutual-auth emitter carries under the shared
24953        // `CiliumNetworkPolicy` body.
24954        assert_eq!(CILIUM_AUTH_MODE_REQUIRED, "required");
24955    }
24956
24957    #[test]
24958    fn cilium_auth_mode_disabled_pins_canonical_value() {
24959        // Peer to `cilium_auth_mode_required_pins_canonical_value` on the
24960        // `Some(false)` opt-out arm of the same
24961        // `MutualAuthenticationMode` OpenAPI schema enum: pin the actual
24962        // string so a typo can't silently rebrand the Cilium `disabled`
24963        // mTLS-skipped scalar-value the rendered CNP's per-rule authn-
24964        // block declares under the explicit `:mtls-required nil` opt-out
24965        // (distinct from the `None` slot-absent arm the renderer maps to
24966        // omit-the-block-entirely). A drifted value (`"Disabled"` /
24967        // `"DISABLED"` / `"off"` / `"skip"`) lands outside the
24968        // `MutualAuthenticationMode` OpenAPI schema enum's admitted set;
24969        // the author's explicit-opt-out intent silently collapses onto the
24970        // cluster-default authentication mode with no field naming the
24971        // mTLS-skipped-scalar-value-drift root cause. Peer to
24972        // `cilium_auth_mode_required_pins_canonical_value` on the
24973        // affirmative arm of the same enum — completes the per-authn-block
24974        // `(mode → {required, disabled})` author-reachable-scalar-value-
24975        // pair single-sourcing the M3 Aplicacao mesh renderer's SPIFFE-
24976        // identity-bound per-edge mTLS enforcement + explicit-opt-out
24977        // contract rests on across the two arms of the `:politicas
24978        // :mtls-required` tristate.
24979        assert_eq!(CILIUM_AUTH_MODE_DISABLED, "disabled");
24980    }
24981
24982    #[test]
24983    fn cilium_auth_modes_carry_lower_case_shape() {
24984        // Cross-axis invariant: the Cilium CNP `MutualAuthenticationMode`
24985        // OpenAPI schema enum admits the closed set `{"required",
24986        // "disabled", "test-always-fail"}` — every admitted value is
24987        // ASCII-lowercase throughout per the Cilium-project convention
24988        // (distinct from the sibling K8s-core `Protocol.TCP` /
24989        // Gateway-API-v1 `ProtocolType.HTTP` all-ASCII-uppercase
24990        // convention the `kube_protocol_tcp_carries_upper_case_shape` /
24991        // `gateway_api_protocol_http_carries_upper_case_shape` pins carry
24992        // on the sibling per-listener L7-parser-selection scalar axis, and
24993        // distinct from the sibling Gateway-API-v1
24994        // `PathMatchType.PathPrefix` UpperCamelCase convention the
24995        // `gateway_api_path_match_type_path_prefix_carries_upper_camel_case_shape`
24996        // pin carries on the sibling per-match request-path-selection
24997        // scalar axis — the Cilium CNP `MutualAuthenticationMode` enum
24998        // grammar does not collapse with either sibling cluster-side
24999        // OpenAPI schema enum's per-value casing convention). Pinning the
25000        // shape here means a future rebrand on either lifted value can't
25001        // silently land a malformed mode-discriminator scalar (uppercase
25002        // `"REQUIRED"` / `"DISABLED"`, UpperCamelCase `"Required"` /
25003        // `"Disabled"`, mixed-case, whitespace) that the Cilium CNP
25004        // `MutualAuthenticationMode` OpenAPI schema enum would reject at
25005        // admission time far from the rebrand commit's source.
25006        for v in [CILIUM_AUTH_MODE_REQUIRED, CILIUM_AUTH_MODE_DISABLED] {
25007            assert!(
25008                !v.is_empty(),
25009                "{v:?} must be non-empty per the Cilium CNP \
25010                 `MutualAuthenticationMode` OpenAPI schema enum grammar"
25011            );
25012            assert!(
25013                v.chars().all(|c| c.is_ascii_lowercase()),
25014                "{v:?} must be ASCII-lowercase throughout per the Cilium \
25015                 CNP `MutualAuthenticationMode` OpenAPI schema enum \
25016                 convention — no uppercase, UpperCamelCase, or whitespace \
25017                 bytes the Cilium-agent-side per-rule mutual-auth-block \
25018                 schema validator would reject"
25019            );
25020        }
25021    }
25022
25023    #[test]
25024    fn cilium_auth_modes_are_distinct() {
25025        // Pin the `MutualAuthenticationMode` enum's per-arm distinctness
25026        // at type-check time: the two author-reachable arms of the typed
25027        // `:politicas :mtls-required` tristate must not collapse onto the
25028        // same scalar-value byte-sequence. A future rebrand that landed
25029        // both lifted constants on the same string (e.g. both `"required"`
25030        // through a copy-paste typo, or both aliased through a shared
25031        // helper) would silently erase the tristate's affirmative /
25032        // explicit-opt-out distinction at the emit boundary — the
25033        // renderer would emit the same scalar under both the `Some(true)`
25034        // and `Some(false)` arms of the closure the
25035        // `single_field_overlay(spec.politicas.mtls_required,
25036        // CILIUM_KEY_MODE, |required| …)` call site carries, collapsing
25037        // the two author intents onto a single Cilium-side enforcement
25038        // policy with no field naming the collapse root cause. Peer to
25039        // the two `cilium_auth_mode_{required,disabled}_pins_canonical_
25040        // value` per-arm pins — completes the per-arm distinctness pin
25041        // set on the closed author-reachable subset of the enum.
25042        assert_ne!(
25043            CILIUM_AUTH_MODE_REQUIRED, CILIUM_AUTH_MODE_DISABLED,
25044            "the two author-reachable arms of the `:mtls-required` \
25045             tristate must land distinct `MutualAuthenticationMode` \
25046             scalar-values"
25047        );
25048    }
25049
25050    #[test]
25051    fn cilium_auth_mode_bijection_dispatches_tristate_arms_onto_scalar_values() {
25052        // Pin the `bool → &'static str` projection every consumer of the
25053        // Cilium `MutualAuthenticationMode` closed-set enum's author-
25054        // reachable scalar-value pair reaches through: `true` (the
25055        // `Some(true)` mTLS-mandatory arm of the typed `:politicas
25056        // :mtls-required` tristate) maps to [`CILIUM_AUTH_MODE_REQUIRED`],
25057        // `false` (the `Some(false)` explicit-opt-out arm) maps to
25058        // [`CILIUM_AUTH_MODE_DISABLED`]. One projection body, both arms of
25059        // the tristate's non-`None` value-space, so a future per-arm
25060        // reassignment (e.g. an upstream Cilium v3 schema swap of the
25061        // `required` ↔ `disabled` scalars, or a per-arm renaming of the
25062        // mTLS-mandatory scalar from `required` to `enforced` / `strict`
25063        // / `mandatory`) lands at the two consts + this projection body
25064        // — not at the caixa-mesh production emitter's closure body and
25065        // the caixa-core `single_field_overlay_threads_typed_value_
25066        // through_closure` generic-helper pin's closure body independently.
25067        // Pin the per-arm round-trip so a future refactor that inverts
25068        // the bool → arm mapping (or collapses one arm) surfaces here
25069        // rather than silently letting a Cilium data-plane pod either
25070        // enforce mTLS where the author asked for skip or skip it where
25071        // the author asked for enforce.
25072        assert_eq!(cilium_auth_mode(true), CILIUM_AUTH_MODE_REQUIRED);
25073        assert_eq!(cilium_auth_mode(false), CILIUM_AUTH_MODE_DISABLED);
25074        // The two arms cover distinct value-space entries — a regression
25075        // that collapses them onto the same scalar surfaces here. Peer
25076        // to `cilium_auth_modes_are_distinct` (the per-arm distinctness
25077        // pin at the const-declaration axis) — this test extends the
25078        // pin onto the projection body axis, so both the raw consts and
25079        // the projection's per-arm dispatch preserve the tristate's
25080        // author-intent distinction end-to-end.
25081        assert_ne!(
25082            cilium_auth_mode(true),
25083            cilium_auth_mode(false),
25084            "cilium_auth_mode must project the two tristate arms onto \
25085             distinct `MutualAuthenticationMode` value-space entries — \
25086             a collapsed-arm regression would silently render both \
25087             `:mtls-required t` and `:mtls-required nil` identically at \
25088             the cluster artifact",
25089        );
25090    }
25091
25092    #[test]
25093    fn gateway_api_key_parent_refs_pins_canonical_value() {
25094        // Pin the actual string so a typo in this lift can't silently
25095        // rebrand the Gateway API `HTTPRoute` parent-Gateway-binding
25096        // container-axis key the rendered HTTPRoute document mounts its
25097        // per-route `[{name}]` parent-Gateway attachment list under. The
25098        // string is part of the cluster-side contract with every
25099        // Gateway-API-conformant gateway implementation (Cilium, Istio,
25100        // Envoy Gateway, NGINX) — the Gateway-API-implementation-side
25101        // per-HTTPRoute reconcile loop keys off this axis to source the
25102        // per-route parent-Gateway attachment list the route is bound
25103        // to; a drifted value (`"parentRef"` / `"parents"` /
25104        // `"parentGateways"`) at either the production emitter or a
25105        // downstream renderer's per-HTTPRoute parent-Gateway-binding
25106        // upsert silently emits an `HTTPRoute` whose parent-Gateway-
25107        // binding axis the Gateway API CRD schema validator drops as
25108        // unknown — the route lands unattached to any Gateway, and
25109        // every external `:entrada` flow the HTTPRoute was authored to
25110        // accept drops at the Gateway API implementation's per-Gateway
25111        // HTTP-listener fan-in with no field naming the parent-Gateway-
25112        // binding-drift root cause. Changing this value is a
25113        // coordinated Gateway API promotion alongside the upstream
25114        // SIG-Network Gateway API deprecation cycle, not an incidental
25115        // edit. Peer to `cilium_key_ports_pins_canonical_value` /
25116        // `cilium_key_from_endpoints_pins_canonical_value` /
25117        // `cilium_key_endpoint_selector_pins_canonical_value` /
25118        // `cilium_key_ingress_pins_canonical_value` /
25119        // `cilium_key_to_ports_pins_canonical_value` on the sibling
25120        // per-CNP-body-axis pin set — begins the per-Gateway-API-
25121        // HTTPRoute-body-axis canonical-string-pin set (`parentRefs`,
25122        // future `hostnames`) the M3 Aplicacao mesh renderer's external
25123        // `:entrada` ingress contract rests on across the Gateway API
25124        // HTTPRoute-side per-route body-shape.
25125        assert_eq!(GATEWAY_API_KEY_PARENT_REFS, "parentRefs");
25126    }
25127
25128    #[test]
25129    fn gateway_api_key_parent_refs_carries_lower_camel_case_shape() {
25130        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25131        // lowerCamelCase identifier per the K8s API conventions
25132        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25133        // "Field names should be lowercase camelCase") — first byte
25134        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25135        // kebab-case or whitespace. Pinning the shape here means a
25136        // future rebrand on the canonical lift can't silently land a
25137        // malformed field-name discriminator (snake_case, kebab-case,
25138        // UpperCamelCase, empty) that the apiserver-side CRD schema
25139        // validator would reject far from the rebrand commit's source.
25140        // Peer to `cilium_key_ports_carries_lower_camel_case_shape` /
25141        // `cilium_key_from_endpoints_carries_lower_camel_case_shape` /
25142        // `cilium_key_endpoint_selector_carries_lower_camel_case_shape`
25143        // / `cilium_key_ingress_carries_lower_camel_case_shape` /
25144        // `cilium_key_to_ports_carries_lower_camel_case_shape` on the
25145        // sibling per-CNP-body-axis grammar-pin set — the lowerCamelCase
25146        // K8s field-name grammar governs every nested schema-field axis
25147        // (including this per-HTTPRoute parent-Gateway-binding-
25148        // container-axis key), same convention.
25149        let v = GATEWAY_API_KEY_PARENT_REFS;
25150        assert!(
25151            !v.is_empty(),
25152            "GATEWAY_API_KEY_PARENT_REFS {v:?} must be non-empty per the K8s API \
25153             lowerCamelCase field-name grammar"
25154        );
25155        let first = v.chars().next().expect("non-empty");
25156        assert!(
25157            first.is_ascii_lowercase(),
25158            "GATEWAY_API_KEY_PARENT_REFS {v:?} first byte {first:?} must be \
25159             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25160             grammar (field names are always lowerCamelCase)"
25161        );
25162        assert!(
25163            v.chars().all(|c| c.is_ascii_alphanumeric()),
25164            "GATEWAY_API_KEY_PARENT_REFS {v:?} must be ASCII-alphanumeric \
25165             throughout per the K8s API field-name grammar — no \
25166             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25167             OpenAPI schema validator would reject"
25168        );
25169    }
25170
25171    #[test]
25172    fn gateway_api_key_backend_refs_pins_canonical_value() {
25173        // Pin the actual string so a typo in this lift can't silently
25174        // rebrand the Gateway API `HTTPRoute` per-rule backend-destination
25175        // container-axis key the rendered HTTPRoute document mounts its
25176        // per-rule `[{name, port}]` backend fan-out list under. The
25177        // string is part of the cluster-side contract with every
25178        // Gateway-API-conformant gateway implementation (Cilium, Istio,
25179        // Envoy Gateway, NGINX) — the Gateway-API-implementation-side
25180        // per-rule L7 dispatch loop keys off this axis to source the
25181        // per-rule backend list the request is forwarded to; a drifted
25182        // value (`"backendRef"` / `"backends"` / `"forwardTo"`) at
25183        // either the production emitter or a downstream renderer's
25184        // per-rule backend-destination upsert silently emits an
25185        // `HTTPRoute` whose per-rule backend fan-out axis the Gateway
25186        // API CRD schema validator drops as unknown — no backend is
25187        // picked at the per-rule L7 dispatch, and every external
25188        // `:entrada` request the rule was authored to route drops at
25189        // the gateway-class-controller's per-rule reconcile with no
25190        // field naming the backend-destination-drift root cause.
25191        // Changing this value is a coordinated Gateway API promotion
25192        // alongside the upstream SIG-Network Gateway API deprecation
25193        // cycle, not an incidental edit. Peer to
25194        // `gateway_api_key_parent_refs_pins_canonical_value` on the
25195        // sibling per-HTTPRoute-body-axis canonical-string-pin surface
25196        // — extends the per-Gateway-API-HTTPRoute-body-axis pin set
25197        // (`parentRefs`, `backendRefs`, future `hostnames`) the M3
25198        // Aplicacao mesh renderer's external `:entrada` ingress
25199        // contract rests on across the Gateway API HTTPRoute-side per-
25200        // route body-shape.
25201        assert_eq!(GATEWAY_API_KEY_BACKEND_REFS, "backendRefs");
25202    }
25203
25204    #[test]
25205    fn gateway_api_key_backend_refs_carries_lower_camel_case_shape() {
25206        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25207        // lowerCamelCase identifier per the K8s API conventions
25208        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25209        // "Field names should be lowercase camelCase") — first byte
25210        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25211        // kebab-case or whitespace. Pinning the shape here means a
25212        // future rebrand on the canonical lift can't silently land a
25213        // malformed field-name discriminator (snake_case, kebab-case,
25214        // UpperCamelCase, empty) that the apiserver-side CRD schema
25215        // validator would reject far from the rebrand commit's source.
25216        // Peer to `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25217        // on the sibling per-HTTPRoute-body-axis grammar-pin surface —
25218        // the lowerCamelCase K8s field-name grammar governs every
25219        // nested schema-field axis (including this per-rule backend-
25220        // destination-container-axis key), same convention.
25221        let v = GATEWAY_API_KEY_BACKEND_REFS;
25222        assert!(
25223            !v.is_empty(),
25224            "GATEWAY_API_KEY_BACKEND_REFS {v:?} must be non-empty per the K8s API \
25225             lowerCamelCase field-name grammar"
25226        );
25227        let first = v.chars().next().expect("non-empty");
25228        assert!(
25229            first.is_ascii_lowercase(),
25230            "GATEWAY_API_KEY_BACKEND_REFS {v:?} first byte {first:?} must be \
25231             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25232             grammar (field names are always lowerCamelCase)"
25233        );
25234        assert!(
25235            v.chars().all(|c| c.is_ascii_alphanumeric()),
25236            "GATEWAY_API_KEY_BACKEND_REFS {v:?} must be ASCII-alphanumeric \
25237             throughout per the K8s API field-name grammar — no \
25238             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25239             OpenAPI schema validator would reject"
25240        );
25241    }
25242
25243    #[test]
25244    fn gateway_api_key_matches_pins_canonical_value() {
25245        // Pin the actual string so a typo in this lift can't silently
25246        // rebrand the Gateway API `HTTPRoute` per-rule route-match
25247        // container-axis key the rendered HTTPRoute document mounts
25248        // its per-rule `[{path: {type, value}}]` route-match fan-out
25249        // list under. The string is part of the cluster-side contract
25250        // with every Gateway-API-conformant gateway implementation
25251        // (Cilium, Istio, Envoy Gateway, NGINX) — the Gateway-API-
25252        // implementation-side per-rule L7 dispatch loop keys off this
25253        // axis to source the per-rule request-selection predicate the
25254        // incoming request line + headers + query must satisfy for
25255        // the rule's backend fan-out to apply; a drifted value
25256        // (`"match"` / `"routeMatches"` / `"predicates"`) at either
25257        // the production emitter or a downstream renderer's per-rule
25258        // route-match upsert silently emits an `HTTPRoute` whose per-
25259        // rule request-selection axis the Gateway API CRD schema
25260        // validator drops as unknown — the per-rule predicate
25261        // degrades to the wildcard match at the gateway-class-
25262        // controller's per-rule reconcile, the rule matches every
25263        // request unconditionally, and every external `:entrada` path
25264        // filter the rule was authored to enforce drops with no field
25265        // naming the route-match-drift root cause. Changing this
25266        // value is a coordinated Gateway API promotion alongside the
25267        // upstream SIG-Network Gateway API deprecation cycle, not an
25268        // incidental edit. Peer to
25269        // `gateway_api_key_backend_refs_pins_canonical_value` /
25270        // `gateway_api_key_parent_refs_pins_canonical_value` on the
25271        // sibling per-HTTPRoute-body-axis canonical-string-pin
25272        // surface — completes the per-rule top-level-axis pin set
25273        // (`matches`, `backendRefs`, `timeouts`, `retry`) the M3
25274        // Aplicacao mesh renderer's external `:entrada` ingress
25275        // contract rests on across the Gateway API HTTPRoute per-rule
25276        // body-shape.
25277        assert_eq!(GATEWAY_API_KEY_MATCHES, "matches");
25278    }
25279
25280    #[test]
25281    fn gateway_api_key_matches_carries_lower_camel_case_shape() {
25282        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25283        // lowerCamelCase identifier per the K8s API conventions
25284        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25285        // "Field names should be lowercase camelCase") — first byte
25286        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25287        // kebab-case or whitespace. Pinning the shape here means a
25288        // future rebrand on the canonical lift can't silently land a
25289        // malformed field-name discriminator (snake_case, kebab-case,
25290        // UpperCamelCase, empty) that the apiserver-side CRD schema
25291        // validator would reject far from the rebrand commit's source.
25292        // Peer to `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25293        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25294        // on the sibling per-HTTPRoute-body-axis grammar-pin surface —
25295        // the lowerCamelCase K8s field-name grammar governs every
25296        // nested schema-field axis (including this per-rule route-
25297        // match-container-axis key), same convention.
25298        let v = GATEWAY_API_KEY_MATCHES;
25299        assert!(
25300            !v.is_empty(),
25301            "GATEWAY_API_KEY_MATCHES {v:?} must be non-empty per the K8s API \
25302             lowerCamelCase field-name grammar"
25303        );
25304        let first = v.chars().next().expect("non-empty");
25305        assert!(
25306            first.is_ascii_lowercase(),
25307            "GATEWAY_API_KEY_MATCHES {v:?} first byte {first:?} must be \
25308             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25309             grammar (field names are always lowerCamelCase)"
25310        );
25311        assert!(
25312            v.chars().all(|c| c.is_ascii_alphanumeric()),
25313            "GATEWAY_API_KEY_MATCHES {v:?} must be ASCII-alphanumeric \
25314             throughout per the K8s API field-name grammar — no \
25315             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25316             OpenAPI schema validator would reject"
25317        );
25318    }
25319
25320    #[test]
25321    fn gateway_api_key_gateway_class_name_pins_canonical_value() {
25322        // Pin the actual string so a typo in this lift can't silently
25323        // rebrand the Gateway API `Gateway` per-Gateway controller-
25324        // binding scalar-axis key the rendered Gateway document
25325        // mounts its per-Gateway `GatewayClass.metadata.name`
25326        // reference under. The string is part of the cluster-side
25327        // contract with every Gateway-API-conformant gateway
25328        // implementation (Cilium, Istio, Envoy Gateway, NGINX) —
25329        // the Gateway-API-implementation-side per-Gateway reconcile
25330        // loop keys off this axis to source the `GatewayClass`
25331        // reference the per-Gateway controller-name-lookup dispatch
25332        // resolves; a drifted value (`"gatewayClass"` /
25333        // `"className"` / `"gatewayClassRef"`) at the production
25334        // emitter silently emits a `Gateway` whose controller-binding
25335        // scalar-axis the Gateway API CRD schema validator drops as
25336        // unknown — no `GatewayClass` is resolved, no `controllerName`
25337        // is looked up, and every external `:entrada` flow the
25338        // Gateway was authored to accept drops at the gateway-class-
25339        // controller's per-Gateway reconcile with no field naming
25340        // the controller-binding-drift root cause. Changing this
25341        // value is a coordinated Gateway API promotion alongside
25342        // the upstream SIG-Network Gateway API deprecation cycle,
25343        // not an incidental edit. Peer to
25344        // `gateway_api_key_listeners_pins_canonical_value` /
25345        // `gateway_api_key_hostname_pins_canonical_value` on the
25346        // sibling per-Gateway-body-axis canonical-string-pin
25347        // surface — completes the per-Gateway-body-axis top-level-
25348        // axis pin set (`gatewayClassName`, `listeners`) the M3
25349        // Aplicacao mesh renderer's external `:entrada` ingress
25350        // contract rests on. Sibling of the peer
25351        // `default_gateway_class_name_pins_canonical_value` on the
25352        // canonical-Gateway-API-`(key, value)`-pair-lift surface
25353        // this lift closes the KEY half of.
25354        assert_eq!(GATEWAY_API_KEY_GATEWAY_CLASS_NAME, "gatewayClassName");
25355    }
25356
25357    #[test]
25358    fn gateway_api_key_gateway_class_name_carries_lower_camel_case_shape() {
25359        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25360        // lowerCamelCase identifier per the K8s API conventions
25361        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25362        // "Field names should be lowercase camelCase") — first byte
25363        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25364        // kebab-case or whitespace. Pinning the shape here means a
25365        // future rebrand on the canonical lift can't silently land a
25366        // malformed field-name discriminator (snake_case, kebab-case,
25367        // UpperCamelCase, empty) that the apiserver-side CRD schema
25368        // validator would reject far from the rebrand commit's source.
25369        // Peer to `gateway_api_key_listeners_carries_lower_camel_case_shape`
25370        // / `gateway_api_key_matches_carries_lower_camel_case_shape`
25371        // on the sibling per-Gateway / per-HTTPRoute-body-axis
25372        // grammar-pin surface — the lowerCamelCase K8s field-name
25373        // grammar governs every nested schema-field axis (including
25374        // this per-Gateway controller-binding scalar-axis key), same
25375        // convention.
25376        let v = GATEWAY_API_KEY_GATEWAY_CLASS_NAME;
25377        assert!(
25378            !v.is_empty(),
25379            "GATEWAY_API_KEY_GATEWAY_CLASS_NAME {v:?} must be non-empty per the K8s API \
25380             lowerCamelCase field-name grammar"
25381        );
25382        let first = v.chars().next().expect("non-empty");
25383        assert!(
25384            first.is_ascii_lowercase(),
25385            "GATEWAY_API_KEY_GATEWAY_CLASS_NAME {v:?} first byte {first:?} must be \
25386             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25387             grammar (field names are always lowerCamelCase)"
25388        );
25389        assert!(
25390            v.chars().all(|c| c.is_ascii_alphanumeric()),
25391            "GATEWAY_API_KEY_GATEWAY_CLASS_NAME {v:?} must be ASCII-alphanumeric \
25392             throughout per the K8s API field-name grammar — no \
25393             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25394             OpenAPI schema validator would reject"
25395        );
25396    }
25397
25398    #[test]
25399    fn gateway_api_key_path_pins_canonical_value() {
25400        // Pin the actual string so a typo in this lift can't silently
25401        // rebrand the Gateway API `HTTPRoute` per-`HTTPRouteMatch`
25402        // path-matcher container-axis key the rendered HTTPRoute
25403        // document mounts its per-match `{type, value}` path-selection
25404        // predicate under. The string is part of the cluster-side
25405        // contract with every Gateway-API-conformant gateway
25406        // implementation (Cilium, Istio, Envoy Gateway, NGINX) — the
25407        // Gateway-API-implementation-side per-rule L7 dispatch loop
25408        // keys off this axis to source the per-match request-path-
25409        // selection predicate the incoming request line's `:path`
25410        // pseudo-header must satisfy under a `type` discriminator of
25411        // `Exact | PathPrefix | RegularExpression`; a drifted value
25412        // (`"pathMatch"` / `"prefix"` / `"url"`) at the production
25413        // emitter silently emits an `HTTPRoute` whose per-match path-
25414        // selection axis the Gateway API CRD schema validator drops
25415        // as unknown — the per-match path predicate degrades to the
25416        // wildcard match at the gateway-class-controller's per-rule
25417        // reconcile, the rule matches every request path
25418        // unconditionally, and every external `:entrada` path filter
25419        // the rule was authored to enforce drops with no field
25420        // naming the path-matcher-drift root cause. Changing this
25421        // value is a coordinated Gateway API promotion alongside the
25422        // upstream SIG-Network Gateway API deprecation cycle, not an
25423        // incidental edit. Peer to
25424        // `gateway_api_key_matches_pins_canonical_value` /
25425        // `gateway_api_key_backend_refs_pins_canonical_value` on the
25426        // sibling per-HTTPRoute-body-axis canonical-string-pin
25427        // surface — nests the per-Gateway-API-HTTPRoute-per-rule-
25428        // body-axis pin set (`matches`, `backendRefs`, `timeouts`,
25429        // `retry`) one level deeper onto the per-`HTTPRouteMatch`
25430        // body-axis surface the M3 Aplicacao mesh renderer's external
25431        // `:entrada` ingress contract rests on.
25432        assert_eq!(GATEWAY_API_KEY_PATH, "path");
25433    }
25434
25435    #[test]
25436    fn gateway_api_key_path_carries_lower_camel_case_shape() {
25437        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25438        // lowerCamelCase identifier per the K8s API conventions
25439        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25440        // "Field names should be lowercase camelCase") — first byte
25441        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25442        // kebab-case or whitespace. Pinning the shape here means a
25443        // future rebrand on the canonical lift can't silently land a
25444        // malformed field-name discriminator (snake_case, kebab-case,
25445        // UpperCamelCase, empty) that the apiserver-side CRD schema
25446        // validator would reject far from the rebrand commit's source.
25447        // Peer to `gateway_api_key_matches_carries_lower_camel_case_shape`
25448        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25449        // on the sibling per-HTTPRoute-body-axis grammar-pin surface —
25450        // the lowerCamelCase K8s field-name grammar governs every
25451        // nested schema-field axis (including this per-`HTTPRouteMatch`
25452        // path-matcher-container-axis key), same convention.
25453        let v = GATEWAY_API_KEY_PATH;
25454        assert!(
25455            !v.is_empty(),
25456            "GATEWAY_API_KEY_PATH {v:?} must be non-empty per the K8s API \
25457             lowerCamelCase field-name grammar"
25458        );
25459        let first = v.chars().next().expect("non-empty");
25460        assert!(
25461            first.is_ascii_lowercase(),
25462            "GATEWAY_API_KEY_PATH {v:?} first byte {first:?} must be \
25463             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25464             grammar (field names are always lowerCamelCase)"
25465        );
25466        assert!(
25467            v.chars().all(|c| c.is_ascii_alphanumeric()),
25468            "GATEWAY_API_KEY_PATH {v:?} must be ASCII-alphanumeric \
25469             throughout per the K8s API field-name grammar — no \
25470             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25471             OpenAPI schema validator would reject"
25472        );
25473    }
25474
25475    #[test]
25476    fn gateway_api_key_value_pins_canonical_value() {
25477        // Pin the actual string so a typo in this lift can't silently
25478        // rebrand the Gateway API `HTTPPathMatch` scalar-payload axis
25479        // key the rendered `HTTPRoute` document mounts its per-match
25480        // request-path-selection scalar payload under. The string is
25481        // part of the cluster-side contract with every Gateway-API-
25482        // conformant gateway implementation (Cilium, Istio, Envoy
25483        // Gateway, NGINX) — the Gateway-API-implementation-side per-
25484        // rule L7 dispatch loop keys off this axis to source the
25485        // per-match request-path string that the sibling `type`
25486        // discriminator (Exact | PathPrefix | RegularExpression) is
25487        // applied against; a drifted value (`"path"` / `"prefix"` /
25488        // `"pattern"` / `"expression"`) at the production emitter
25489        // silently emits an `HTTPRoute` whose per-match request-path
25490        // scalar the Gateway API CRD schema validator drops as
25491        // unknown — the per-match path predicate degrades to the
25492        // wildcard match at the gateway-class-controller's per-rule
25493        // reconcile, the rule matches every request path
25494        // unconditionally, and every external `:entrada` path filter
25495        // the rule was authored to enforce drops with no field
25496        // naming the `HTTPPathMatch`-scalar-payload-drift root cause.
25497        // Changing this value is a coordinated Gateway API promotion
25498        // alongside the upstream SIG-Network Gateway API deprecation
25499        // cycle, not an incidental edit. Peer to
25500        // `gateway_api_key_path_pins_canonical_value` on the sibling
25501        // per-`HTTPRouteMatch`-body-axis canonical-string-pin surface
25502        // — nests the per-Gateway-API-HTTPRoute-per-match-body-axis
25503        // pin set (`path` container-axis, `value` scalar-payload key)
25504        // one level deeper onto the per-`HTTPPathMatch` body-axis
25505        // surface the M3 Aplicacao mesh renderer's external `:entrada`
25506        // ingress contract rests on.
25507        assert_eq!(GATEWAY_API_KEY_VALUE, "value");
25508    }
25509
25510    #[test]
25511    fn gateway_api_key_value_carries_lower_camel_case_shape() {
25512        // Cross-axis invariant: a Kubernetes CRD schema field name is
25513        // a lowerCamelCase identifier per the K8s API conventions
25514        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25515        // "Field names should be lowercase camelCase") — first byte
25516        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25517        // kebab-case or whitespace. Pinning the shape here means a
25518        // future rebrand on the canonical lift can't silently land a
25519        // malformed field-name discriminator (snake_case, kebab-case,
25520        // UpperCamelCase, empty) that the apiserver-side CRD schema
25521        // validator would reject far from the rebrand commit's source.
25522        // Peer to `gateway_api_key_path_carries_lower_camel_case_shape`
25523        // on the sibling per-`HTTPRouteMatch`-body-axis grammar-pin
25524        // surface — the lowerCamelCase K8s field-name grammar governs
25525        // every nested schema-field axis (including this per-
25526        // `HTTPPathMatch` scalar-payload-axis key), same convention.
25527        let v = GATEWAY_API_KEY_VALUE;
25528        assert!(
25529            !v.is_empty(),
25530            "GATEWAY_API_KEY_VALUE {v:?} must be non-empty per the K8s API \
25531             lowerCamelCase field-name grammar"
25532        );
25533        let first = v.chars().next().expect("non-empty");
25534        assert!(
25535            first.is_ascii_lowercase(),
25536            "GATEWAY_API_KEY_VALUE {v:?} first byte {first:?} must be \
25537             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25538             grammar (field names are always lowerCamelCase)"
25539        );
25540        assert!(
25541            v.chars().all(|c| c.is_ascii_alphanumeric()),
25542            "GATEWAY_API_KEY_VALUE {v:?} must be ASCII-alphanumeric \
25543             throughout per the K8s API field-name grammar — no \
25544             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25545             OpenAPI schema validator would reject"
25546        );
25547    }
25548
25549    #[test]
25550    fn gateway_api_key_value_distinct_from_gateway_api_key_path() {
25551        // Cross-axis invariant: the `HTTPPathMatch` scalar-payload key
25552        // (`value`) and its parent-container-axis key (`path`) name
25553        // *distinct* Gateway-API-side schema fields — the parent is a
25554        // container that hangs off the per-`HTTPRouteMatch`
25555        // `matches[]` entry, the child is the scalar payload that
25556        // rides inside the parent's `{type, value}` two-axis body.
25557        // Under the sibling K8s API conventions grammar
25558        // (`gateway_api_key_value_carries_lower_camel_case_shape` /
25559        // `gateway_api_key_path_carries_lower_camel_case_shape`) both
25560        // are ASCII-lowerCamelCase identifiers, so a same-shape
25561        // grammar-pin alone doesn't prevent a future rebrand from
25562        // silently collapsing the two axes onto the same string —
25563        // pinning inequality here surfaces that footgun at exactly
25564        // this build-time lift instead of at apply time as an
25565        // `HTTPRoute` whose per-match `path` container-body is
25566        // structurally malformed (`{path: <str>, path: <str>}` — the
25567        // apiserver's OpenAPI schema validator drops the whole match
25568        // block, the per-match path predicate degrades to the
25569        // wildcard match at the gateway-class-controller's per-rule
25570        // reconcile, the rule matches every request path
25571        // unconditionally, and every external `:entrada` path filter
25572        // the rule was authored to enforce drops with no field
25573        // naming the container/scalar-collapse root cause).
25574        assert_ne!(
25575            GATEWAY_API_KEY_VALUE, GATEWAY_API_KEY_PATH,
25576            "GATEWAY_API_KEY_VALUE ({GATEWAY_API_KEY_VALUE:?}) must not \
25577             collapse onto GATEWAY_API_KEY_PATH ({GATEWAY_API_KEY_PATH:?}) \
25578             — the two name distinct Gateway API `HTTPPathMatch` axes \
25579             (parent container vs. inner scalar payload) that must \
25580             remain independently addressable in the emitted \
25581             `HTTPRoute` per-match body"
25582        );
25583    }
25584
25585    #[test]
25586    fn gateway_api_key_listeners_pins_canonical_value() {
25587        // Pin the actual string so a typo in this lift can't silently
25588        // rebrand the Gateway API `Gateway` per-listener-set container-
25589        // axis key the rendered Gateway document mounts its per-Gateway
25590        // `[{name, port, protocol, hostname}]` L7-listener fan-out list
25591        // under. The string is part of the cluster-side contract with
25592        // every Gateway-API-conformant gateway implementation (Cilium,
25593        // Istio, Envoy Gateway, NGINX) — the Gateway-API-implementation-
25594        // side per-Gateway reconcile loop keys off this axis to source
25595        // the per-Gateway L7-listener fan-out the external `:entrada`
25596        // flow the Gateway was authored to accept lands on; a drifted
25597        // value (`"listener"` / `"listen"` / `"servers"`) at either the
25598        // production emitter or a downstream renderer's per-Gateway L7-
25599        // listener-set upsert silently emits a `Gateway` whose L7-
25600        // listener-set axis the Gateway API CRD schema validator drops
25601        // as unknown — no listener is opened, and every external
25602        // `:entrada` flow drops at the gateway-class-controller's per-
25603        // Gateway reconcile with no field naming the L7-listener-set-
25604        // drift root cause. Changing this value is a coordinated
25605        // Gateway API promotion alongside the upstream SIG-Network
25606        // Gateway API deprecation cycle, not an incidental edit. Peer
25607        // to `gateway_api_key_parent_refs_pins_canonical_value` /
25608        // `gateway_api_key_backend_refs_pins_canonical_value` on the
25609        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
25610        // surface — extends the per-Gateway-API-CRD-body-axis pin set
25611        // (`parentRefs`, `backendRefs`, `listeners`, future
25612        // `hostnames`) the M3 Aplicacao mesh renderer's external
25613        // `:entrada` ingress contract rests on across the Gateway API
25614        // CRD-side body-shape.
25615        assert_eq!(GATEWAY_API_KEY_LISTENERS, "listeners");
25616    }
25617
25618    #[test]
25619    fn gateway_api_key_listeners_carries_lower_camel_case_shape() {
25620        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25621        // lowerCamelCase identifier per the K8s API conventions
25622        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25623        // "Field names should be lowercase camelCase") — first byte
25624        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25625        // kebab-case or whitespace. Pinning the shape here means a
25626        // future rebrand on the canonical lift can't silently land a
25627        // malformed field-name discriminator (snake_case, kebab-case,
25628        // UpperCamelCase, empty) that the apiserver-side CRD schema
25629        // validator would reject far from the rebrand commit's source.
25630        // Peer to `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25631        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25632        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
25633        // surface — the lowerCamelCase K8s field-name grammar governs
25634        // every nested schema-field axis (including this per-Gateway
25635        // L7-listener-set-container-axis key), same convention.
25636        let v = GATEWAY_API_KEY_LISTENERS;
25637        assert!(
25638            !v.is_empty(),
25639            "GATEWAY_API_KEY_LISTENERS {v:?} must be non-empty per the K8s API \
25640             lowerCamelCase field-name grammar"
25641        );
25642        let first = v.chars().next().expect("non-empty");
25643        assert!(
25644            first.is_ascii_lowercase(),
25645            "GATEWAY_API_KEY_LISTENERS {v:?} first byte {first:?} must be \
25646             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25647             grammar (field names are always lowerCamelCase)"
25648        );
25649        assert!(
25650            v.chars().all(|c| c.is_ascii_alphanumeric()),
25651            "GATEWAY_API_KEY_LISTENERS {v:?} must be ASCII-alphanumeric \
25652             throughout per the K8s API field-name grammar — no \
25653             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25654             OpenAPI schema validator would reject"
25655        );
25656    }
25657
25658    #[test]
25659    fn gateway_api_key_hostname_pins_canonical_value() {
25660        // Pin the actual string so a typo in this lift can't silently
25661        // rebrand the Gateway API `Gateway` per-listener DNS-host-
25662        // discriminator axis key the rendered Gateway document mounts
25663        // each listener's virtual-host filter under. The string is part
25664        // of the cluster-side contract with every Gateway-API-conformant
25665        // gateway implementation (Cilium, Istio, Envoy Gateway, NGINX) —
25666        // the Gateway-API-implementation-side per-listener SNI /
25667        // `Host:`-header dispatch loop keys off this axis to source the
25668        // per-listener virtual-host filter each listener's inbound
25669        // traffic is scoped against; a drifted value (`"host"` /
25670        // `"vhost"` / `"serverName"`) at either the production emitter
25671        // or a downstream renderer's per-listener DNS-host-discriminator
25672        // upsert silently emits a `Gateway` whose per-listener virtual-
25673        // host filter axis the Gateway API CRD schema validator drops as
25674        // unknown — the listener accepts traffic on the wildcard host
25675        // rather than the typed `:entrada :host` the Aplicacao author
25676        // declared, and every external `:entrada` flow the listener was
25677        // authored to accept lands on the wrong virtual-host filter with
25678        // no field naming the DNS-host-discriminator-drift root cause.
25679        // Changing this value is a coordinated Gateway API promotion
25680        // alongside the upstream SIG-Network Gateway API deprecation
25681        // cycle, not an incidental edit. Peer to
25682        // `gateway_api_key_listeners_pins_canonical_value` /
25683        // `gateway_api_key_parent_refs_pins_canonical_value` /
25684        // `gateway_api_key_backend_refs_pins_canonical_value` on the
25685        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
25686        // surface — nests the per-Gateway-API-CRD-body-axis pin
25687        // discipline one level deeper onto the sibling per-listener
25688        // body-axis surface, extending the per-Gateway-API-CRD-body-
25689        // axis pin set (`parentRefs`, `backendRefs`, `listeners`,
25690        // `hostname`, future `hostnames`) the M3 Aplicacao mesh
25691        // renderer's external `:entrada` ingress contract rests on
25692        // across the Gateway API CRD-side body-shape.
25693        assert_eq!(GATEWAY_API_KEY_HOSTNAME, "hostname");
25694    }
25695
25696    #[test]
25697    fn gateway_api_key_hostname_carries_lower_camel_case_shape() {
25698        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25699        // lowerCamelCase identifier per the K8s API conventions
25700        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25701        // "Field names should be lowercase camelCase") — first byte
25702        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25703        // kebab-case or whitespace. Pinning the shape here means a
25704        // future rebrand on the canonical lift can't silently land a
25705        // malformed field-name discriminator (snake_case, kebab-case,
25706        // UpperCamelCase, empty) that the apiserver-side CRD schema
25707        // validator would reject far from the rebrand commit's source.
25708        // Peer to `gateway_api_key_listeners_carries_lower_camel_case_shape`
25709        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25710        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25711        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
25712        // surface — the lowerCamelCase K8s field-name grammar governs
25713        // every nested schema-field axis (including this per-listener
25714        // DNS-host-discriminator-axis key), same convention.
25715        let v = GATEWAY_API_KEY_HOSTNAME;
25716        assert!(
25717            !v.is_empty(),
25718            "GATEWAY_API_KEY_HOSTNAME {v:?} must be non-empty per the K8s API \
25719             lowerCamelCase field-name grammar"
25720        );
25721        let first = v.chars().next().expect("non-empty");
25722        assert!(
25723            first.is_ascii_lowercase(),
25724            "GATEWAY_API_KEY_HOSTNAME {v:?} first byte {first:?} must be \
25725             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25726             grammar (field names are always lowerCamelCase)"
25727        );
25728        assert!(
25729            v.chars().all(|c| c.is_ascii_alphanumeric()),
25730            "GATEWAY_API_KEY_HOSTNAME {v:?} must be ASCII-alphanumeric \
25731             throughout per the K8s API field-name grammar — no \
25732             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25733             OpenAPI schema validator would reject"
25734        );
25735    }
25736
25737    #[test]
25738    fn gateway_api_key_hostnames_pins_canonical_value() {
25739        // Pin the actual string so a typo in this lift can't silently
25740        // rebrand the Gateway API `HTTPRoute` spec-level DNS-host-filter
25741        // axis key the rendered HTTPRoute document mounts each route's
25742        // per-route virtual-host filter list under. The string is part
25743        // of the cluster-side contract with every Gateway-API-conformant
25744        // gateway implementation (Cilium, Istio, Envoy Gateway, NGINX) —
25745        // the Gateway-API-implementation-side per-route SNI /
25746        // `Host:`-header dispatch loop keys off this axis to source the
25747        // per-route virtual-host filter list each route's inbound
25748        // traffic is scoped against; a drifted value (`"hosts"` /
25749        // `"vhosts"` / `"serverNames"`) at either the production emitter
25750        // or a downstream renderer's per-route DNS-host-filter upsert
25751        // silently emits an `HTTPRoute` whose per-route virtual-host
25752        // filter axis the Gateway API CRD schema validator drops as
25753        // unknown — the route accepts traffic on every host the parent
25754        // Gateway's listener accepts rather than the typed `:entrada
25755        // :host` the Aplicacao author declared, and every external
25756        // `:entrada` flow the route was authored to accept lands on the
25757        // wildcard virtual-host filter with no field naming the DNS-
25758        // host-filter-drift root cause. Changing this value is a
25759        // coordinated Gateway API promotion alongside the upstream
25760        // SIG-Network Gateway API deprecation cycle, not an incidental
25761        // edit. Peer to
25762        // `gateway_api_key_hostname_pins_canonical_value` /
25763        // `gateway_api_key_listeners_pins_canonical_value` /
25764        // `gateway_api_key_parent_refs_pins_canonical_value` /
25765        // `gateway_api_key_backend_refs_pins_canonical_value` on the
25766        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
25767        // surface — closes the per-Gateway-API-CRD `HTTPRoute` per-route
25768        // body-axis pin pair across the singular / plural DNS-host
25769        // discriminator surface (`hostname` at the parent-Gateway per-
25770        // listener discriminator + `hostnames` at the child HTTPRoute
25771        // per-route filter list), so both halves of the DNS-host-
25772        // discriminator convention across the `(Gateway, HTTPRoute)`
25773        // pair the M3 Aplicacao mesh renderer's external `:entrada`
25774        // ingress contract emits together now carry one lifted
25775        // canonical-string pin apiece.
25776        assert_eq!(GATEWAY_API_KEY_HOSTNAMES, "hostnames");
25777    }
25778
25779    #[test]
25780    fn gateway_api_key_hostnames_carries_lower_camel_case_shape() {
25781        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25782        // lowerCamelCase identifier per the K8s API conventions
25783        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25784        // "Field names should be lowercase camelCase") — first byte
25785        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25786        // kebab-case or whitespace. Pinning the shape here means a
25787        // future rebrand on the canonical lift can't silently land a
25788        // malformed field-name discriminator (snake_case, kebab-case,
25789        // UpperCamelCase, empty) that the apiserver-side CRD schema
25790        // validator would reject far from the rebrand commit's source.
25791        // Peer to `gateway_api_key_hostname_carries_lower_camel_case_shape`
25792        // / `gateway_api_key_listeners_carries_lower_camel_case_shape`
25793        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25794        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25795        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
25796        // surface — the lowerCamelCase K8s field-name grammar governs
25797        // every nested schema-field axis (including this per-route DNS-
25798        // host-filter-axis key), same convention.
25799        let v = GATEWAY_API_KEY_HOSTNAMES;
25800        assert!(
25801            !v.is_empty(),
25802            "GATEWAY_API_KEY_HOSTNAMES {v:?} must be non-empty per the K8s API \
25803             lowerCamelCase field-name grammar"
25804        );
25805        let first = v.chars().next().expect("non-empty");
25806        assert!(
25807            first.is_ascii_lowercase(),
25808            "GATEWAY_API_KEY_HOSTNAMES {v:?} first byte {first:?} must be \
25809             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25810             grammar (field names are always lowerCamelCase)"
25811        );
25812        assert!(
25813            v.chars().all(|c| c.is_ascii_alphanumeric()),
25814            "GATEWAY_API_KEY_HOSTNAMES {v:?} must be ASCII-alphanumeric \
25815             throughout per the K8s API field-name grammar — no \
25816             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25817             OpenAPI schema validator would reject"
25818        );
25819    }
25820
25821    #[test]
25822    fn gateway_api_key_timeouts_pins_canonical_value() {
25823        // Pin the actual string so a typo in this lift can't silently
25824        // rebrand the Gateway API `HTTPRoute` per-rule request-timeout-
25825        // policy body-axis key the rendered HTTPRoute document mounts
25826        // each rule's per-rule `:politicas :timeout` overlay under. The
25827        // string is part of the cluster-side contract with every
25828        // Gateway-API-conformant gateway implementation (Cilium, Istio,
25829        // Envoy Gateway, NGINX) — the Gateway-API-implementation-side
25830        // per-rule request-dispatch loop keys off this axis to source
25831        // the per-rule wall-clock deadline each accepted request is
25832        // bounded against; a drifted value (`"timeout"` (singular) /
25833        // `"timeoutPolicy"` / `"deadlines"`) at either the production
25834        // emitter or a downstream renderer's per-rule timeout-policy
25835        // upsert silently emits an `HTTPRoute` whose per-rule request-
25836        // timeout policy axis the Gateway API CRD schema validator
25837        // drops as unknown — the route accepts every inbound request
25838        // with no per-rule wall-clock deadline (the "no infinite
25839        // blocking" guarantee MESH-COMPOSITION.md §V mandates for every
25840        // rendered per-`:politicas` mesh-composition edge silently
25841        // regresses to the pre-overlay unbounded-request semantic), and
25842        // every external `:entrada` flow the route was authored to
25843        // bound by the typed `:politicas :timeout` slot runs to
25844        // whatever backend deadline the resolved backend's downstream
25845        // infrastructure picks with no field naming the per-rule-
25846        // timeout-policy-drift root cause. Changing this value is a
25847        // coordinated Gateway API promotion alongside the upstream
25848        // SIG-Network Gateway API deprecation cycle, not an incidental
25849        // edit. Peer to
25850        // `gateway_api_key_hostnames_pins_canonical_value` /
25851        // `gateway_api_key_hostname_pins_canonical_value` /
25852        // `gateway_api_key_listeners_pins_canonical_value` /
25853        // `gateway_api_key_parent_refs_pins_canonical_value` /
25854        // `gateway_api_key_backend_refs_pins_canonical_value` on the
25855        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
25856        // surface — extends the per-Gateway-API-`HTTPRoute` per-rule
25857        // body-axis pin set (`backendRefs`, future per-rule sibling
25858        // axes) onto the load-bearing per-rule request-timeout-policy
25859        // axis the M3 Aplicacao mesh renderer's per-`:politicas
25860        // :timeout` overlay lands under.
25861        assert_eq!(GATEWAY_API_KEY_TIMEOUTS, "timeouts");
25862    }
25863
25864    #[test]
25865    fn gateway_api_key_timeouts_carries_lower_camel_case_shape() {
25866        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25867        // lowerCamelCase identifier per the K8s API conventions
25868        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25869        // "Field names should be lowercase camelCase") — first byte
25870        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25871        // kebab-case or whitespace. Pinning the shape here means a
25872        // future rebrand on the canonical lift can't silently land a
25873        // malformed field-name discriminator (snake_case, kebab-case,
25874        // UpperCamelCase, empty) that the apiserver-side CRD schema
25875        // validator would reject far from the rebrand commit's source.
25876        // Peer to `gateway_api_key_hostnames_carries_lower_camel_case_shape`
25877        // / `gateway_api_key_hostname_carries_lower_camel_case_shape`
25878        // / `gateway_api_key_listeners_carries_lower_camel_case_shape`
25879        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25880        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25881        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
25882        // surface — the lowerCamelCase K8s field-name grammar governs
25883        // every nested schema-field axis (including this per-rule
25884        // request-timeout-policy-axis key), same convention.
25885        let v = GATEWAY_API_KEY_TIMEOUTS;
25886        assert!(
25887            !v.is_empty(),
25888            "GATEWAY_API_KEY_TIMEOUTS {v:?} must be non-empty per the K8s API \
25889             lowerCamelCase field-name grammar"
25890        );
25891        let first = v.chars().next().expect("non-empty");
25892        assert!(
25893            first.is_ascii_lowercase(),
25894            "GATEWAY_API_KEY_TIMEOUTS {v:?} first byte {first:?} must be \
25895             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25896             grammar (field names are always lowerCamelCase)"
25897        );
25898        assert!(
25899            v.chars().all(|c| c.is_ascii_alphanumeric()),
25900            "GATEWAY_API_KEY_TIMEOUTS {v:?} must be ASCII-alphanumeric \
25901             throughout per the K8s API field-name grammar — no \
25902             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25903             OpenAPI schema validator would reject"
25904        );
25905    }
25906
25907    #[test]
25908    fn gateway_api_key_retry_pins_canonical_value() {
25909        // Pin the actual string so a typo in this lift can't silently
25910        // rebrand the Gateway API `HTTPRoute` per-rule retry-policy
25911        // body-axis key the rendered HTTPRoute document mounts each
25912        // rule's per-rule `:politicas :retries` overlay under. The
25913        // string is part of the cluster-side contract with every
25914        // Gateway-API-conformant gateway implementation (Cilium, Istio,
25915        // Envoy Gateway, NGINX) — the Gateway-API-implementation-side
25916        // per-rule request-dispatch loop keys off this axis to source
25917        // the per-rule retry budget each failed backend attempt count
25918        // is bounded against; a drifted value (`"retries"` (plural) /
25919        // `"retryPolicy"` / `"budget"`) at either the production
25920        // emitter or a downstream renderer's per-rule retry-policy
25921        // upsert silently emits an `HTTPRoute` whose per-rule retry-
25922        // budget axis the Gateway API CRD schema validator drops as
25923        // unknown — the route accepts every inbound request with no
25924        // per-rule retry budget (the "no infinite retrying without
25925        // bound" guarantee MESH-COMPOSITION.md §V mandates for every
25926        // rendered per-`:politicas` mesh-composition edge silently
25927        // regresses to the pre-overlay unbounded-retry semantic), and
25928        // every external `:entrada` flow the route was authored to cap
25929        // by the typed `:politicas :retries` slot runs to whatever
25930        // retry policy the resolved backend's downstream infrastructure
25931        // picks with no field naming the per-rule-retry-policy-drift
25932        // root cause. Changing this value is a coordinated Gateway API
25933        // promotion alongside the upstream SIG-Network Gateway API
25934        // deprecation cycle, not an incidental edit. Peer to
25935        // `gateway_api_key_timeouts_pins_canonical_value` /
25936        // `gateway_api_key_hostnames_pins_canonical_value` /
25937        // `gateway_api_key_hostname_pins_canonical_value` /
25938        // `gateway_api_key_listeners_pins_canonical_value` /
25939        // `gateway_api_key_parent_refs_pins_canonical_value` /
25940        // `gateway_api_key_backend_refs_pins_canonical_value` on the
25941        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
25942        // surface — closes the per-Gateway-API-`HTTPRoute`-per-rule
25943        // `:politicas` overlay axis pair (`timeouts` for `:politicas
25944        // :timeout`, `retry` for `:politicas :retries`) both
25945        // MESH-COMPOSITION.md §V "no infinite blocking / no infinite
25946        // retrying" guarantees rest on.
25947        assert_eq!(GATEWAY_API_KEY_RETRY, "retry");
25948    }
25949
25950    #[test]
25951    fn gateway_api_key_retry_carries_lower_camel_case_shape() {
25952        // Cross-axis invariant: a Kubernetes CRD schema field name is a
25953        // lowerCamelCase identifier per the K8s API conventions
25954        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
25955        // "Field names should be lowercase camelCase") — first byte
25956        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
25957        // kebab-case or whitespace. Pinning the shape here means a
25958        // future rebrand on the canonical lift can't silently land a
25959        // malformed field-name discriminator (snake_case, kebab-case,
25960        // UpperCamelCase, empty) that the apiserver-side CRD schema
25961        // validator would reject far from the rebrand commit's source.
25962        // Peer to `gateway_api_key_timeouts_carries_lower_camel_case_shape`
25963        // / `gateway_api_key_hostnames_carries_lower_camel_case_shape`
25964        // / `gateway_api_key_hostname_carries_lower_camel_case_shape`
25965        // / `gateway_api_key_listeners_carries_lower_camel_case_shape`
25966        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
25967        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
25968        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
25969        // surface — the lowerCamelCase K8s field-name grammar governs
25970        // every nested schema-field axis (including this per-rule
25971        // retry-policy-axis key), same convention.
25972        let v = GATEWAY_API_KEY_RETRY;
25973        assert!(
25974            !v.is_empty(),
25975            "GATEWAY_API_KEY_RETRY {v:?} must be non-empty per the K8s API \
25976             lowerCamelCase field-name grammar"
25977        );
25978        let first = v.chars().next().expect("non-empty");
25979        assert!(
25980            first.is_ascii_lowercase(),
25981            "GATEWAY_API_KEY_RETRY {v:?} first byte {first:?} must be \
25982             ASCII-lowercase per the K8s API lowerCamelCase field-name \
25983             grammar (field names are always lowerCamelCase)"
25984        );
25985        assert!(
25986            v.chars().all(|c| c.is_ascii_alphanumeric()),
25987            "GATEWAY_API_KEY_RETRY {v:?} must be ASCII-alphanumeric \
25988             throughout per the K8s API field-name grammar — no \
25989             snake_case, kebab-case, or whitespace bytes the apiserver-side \
25990             OpenAPI schema validator would reject"
25991        );
25992    }
25993
25994    #[test]
25995    fn gateway_api_key_attempts_pins_canonical_value() {
25996        // Pin the actual string so a typo in this lift can't silently
25997        // rebrand the Gateway API `HTTPRoute` per-rule retry-policy
25998        // `attempts` leaf scalar-key the rendered HTTPRoute document
25999        // mounts each rule's per-rule `:politicas :retries` typed `u32`
26000        // attempt count under. The string is part of the cluster-side
26001        // contract with every Gateway-API-conformant gateway
26002        // implementation (Cilium, Istio, Envoy Gateway, NGINX) — the
26003        // Gateway-API-implementation-side per-rule request-dispatch
26004        // loop keys off this leaf to source the per-rule retry attempt
26005        // budget each failed backend attempt count is bounded against;
26006        // a drifted value (`"attempt"` (singular) / `"count"` /
26007        // `"tries"` / `"maxAttempts"`) at either the production
26008        // emitter or a downstream renderer's per-rule retry-attempts
26009        // upsert silently emits an `HTTPRoute` whose per-rule retry-
26010        // attempts leaf the Gateway API CRD schema validator drops as
26011        // unknown — the retry sub-shape parses as an empty
26012        // `HTTPRouteRetry` with the typed `u32` attempt count silently
26013        // discarded, the route accepts every inbound request with no
26014        // per-rule retry budget (the "no infinite retrying without
26015        // bound" guarantee MESH-COMPOSITION.md §V mandates for every
26016        // rendered per-`:politicas` mesh-composition edge silently
26017        // regresses to the pre-overlay unbounded-retry semantic), and
26018        // every external `:entrada` flow the route was authored to cap
26019        // by the typed `:politicas :retries` slot runs to whatever
26020        // retry policy the resolved backend's downstream infrastructure
26021        // picks with no field naming the per-rule-retry-attempts-leaf-
26022        // key-drift root cause. Changing this value is a coordinated
26023        // Gateway API promotion alongside the upstream SIG-Network
26024        // Gateway API deprecation cycle, not an incidental edit. Peer
26025        // to `gateway_api_key_retry_pins_canonical_value` /
26026        // `gateway_api_key_timeouts_pins_canonical_value` /
26027        // `gateway_api_key_hostnames_pins_canonical_value` /
26028        // `gateway_api_key_hostname_pins_canonical_value` /
26029        // `gateway_api_key_listeners_pins_canonical_value` /
26030        // `gateway_api_key_parent_refs_pins_canonical_value` /
26031        // `gateway_api_key_backend_refs_pins_canonical_value` on the
26032        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
26033        // surface — closes the parent-leaf axis pair (`retry`
26034        // container + `attempts` leaf) both MESH-COMPOSITION.md §V
26035        // "no infinite retrying" guarantees rest on, one nesting
26036        // level deeper than the parent per-rule retry-policy
26037        // container axis (`retry`).
26038        assert_eq!(GATEWAY_API_KEY_ATTEMPTS, "attempts");
26039    }
26040
26041    #[test]
26042    fn gateway_api_key_attempts_carries_lower_camel_case_shape() {
26043        // Cross-axis invariant: a Kubernetes CRD schema field name is a
26044        // lowerCamelCase identifier per the K8s API conventions
26045        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
26046        // "Field names should be lowercase camelCase") — first byte
26047        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
26048        // kebab-case or whitespace. Pinning the shape here means a
26049        // future rebrand on the canonical lift can't silently land a
26050        // malformed field-name discriminator (snake_case, kebab-case,
26051        // UpperCamelCase, empty) that the apiserver-side CRD schema
26052        // validator would reject far from the rebrand commit's source.
26053        // Peer to `gateway_api_key_retry_carries_lower_camel_case_shape`
26054        // / `gateway_api_key_timeouts_carries_lower_camel_case_shape`
26055        // / `gateway_api_key_hostnames_carries_lower_camel_case_shape`
26056        // / `gateway_api_key_hostname_carries_lower_camel_case_shape`
26057        // / `gateway_api_key_listeners_carries_lower_camel_case_shape`
26058        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
26059        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
26060        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
26061        // surface — the lowerCamelCase K8s field-name grammar governs
26062        // every nested schema-field axis (including this per-rule
26063        // retry-attempts-leaf-key), same convention.
26064        let v = GATEWAY_API_KEY_ATTEMPTS;
26065        assert!(
26066            !v.is_empty(),
26067            "GATEWAY_API_KEY_ATTEMPTS {v:?} must be non-empty per the K8s API \
26068             lowerCamelCase field-name grammar"
26069        );
26070        let first = v.chars().next().expect("non-empty");
26071        assert!(
26072            first.is_ascii_lowercase(),
26073            "GATEWAY_API_KEY_ATTEMPTS {v:?} first byte {first:?} must be \
26074             ASCII-lowercase per the K8s API lowerCamelCase field-name \
26075             grammar (field names are always lowerCamelCase)"
26076        );
26077        assert!(
26078            v.chars().all(|c| c.is_ascii_alphanumeric()),
26079            "GATEWAY_API_KEY_ATTEMPTS {v:?} must be ASCII-alphanumeric \
26080             throughout per the K8s API field-name grammar — no \
26081             snake_case, kebab-case, or whitespace bytes the apiserver-side \
26082             OpenAPI schema validator would reject"
26083        );
26084    }
26085
26086    #[test]
26087    fn gateway_api_key_request_pins_canonical_value() {
26088        // Pin the actual string so a typo in this lift can't silently
26089        // rebrand the Gateway API `HTTPRoute` per-rule request-timeout-
26090        // policy `request` leaf scalar-key the rendered HTTPRoute
26091        // document mounts each rule's per-rule `:politicas :timeout`
26092        // typed K8s-duration string under. The string is part of the
26093        // cluster-side contract with every Gateway-API-conformant
26094        // gateway implementation (Cilium, Istio, Envoy Gateway, NGINX)
26095        // — the Gateway-API-implementation-side per-rule request-
26096        // dispatch loop keys off this leaf to source the per-rule
26097        // request wall-clock deadline each inbound request is bounded
26098        // against; a drifted value (`"deadline"` / `"requestTimeout"`
26099        // / `"timeout"` / `"upstreamRequest"`) at either the production
26100        // emitter or a downstream renderer's per-rule request-deadline
26101        // upsert silently emits an `HTTPRoute` whose per-rule request-
26102        // deadline leaf the Gateway API CRD schema validator drops as
26103        // unknown — the timeouts sub-shape parses as an empty
26104        // `HTTPRouteTimeouts` with the typed duration silently
26105        // discarded, the route accepts every inbound request with no
26106        // per-rule request deadline (the "no infinite blocking"
26107        // guarantee MESH-COMPOSITION.md §V mandates for every rendered
26108        // per-`:politicas` mesh-composition edge silently regresses to
26109        // the pre-overlay unbounded-blocking semantic), and every
26110        // external `:entrada` flow the route was authored to cap by
26111        // the typed `:politicas :timeout` slot runs to whatever
26112        // request-deadline the resolved backend's downstream
26113        // infrastructure picks with no field naming the per-rule-
26114        // request-deadline-leaf-key-drift root cause. Changing this
26115        // value is a coordinated Gateway API promotion alongside the
26116        // upstream SIG-Network Gateway API deprecation cycle, not an
26117        // incidental edit. Peer to
26118        // `gateway_api_key_attempts_pins_canonical_value` /
26119        // `gateway_api_key_retry_pins_canonical_value` /
26120        // `gateway_api_key_timeouts_pins_canonical_value` /
26121        // `gateway_api_key_hostnames_pins_canonical_value` /
26122        // `gateway_api_key_hostname_pins_canonical_value` /
26123        // `gateway_api_key_listeners_pins_canonical_value` /
26124        // `gateway_api_key_parent_refs_pins_canonical_value` /
26125        // `gateway_api_key_backend_refs_pins_canonical_value` on the
26126        // sibling per-Gateway-API-CRD-body-axis canonical-string-pin
26127        // surface — closes the second parent-leaf axis pair
26128        // (`timeouts` container + `request` leaf) both
26129        // MESH-COMPOSITION.md §V "no infinite blocking / no infinite
26130        // retrying" guarantees rest on, sibling to the parent-leaf
26131        // pair (`retry` container + `attempts` leaf) closed in
26132        // e2e136b.
26133        assert_eq!(GATEWAY_API_KEY_REQUEST, "request");
26134    }
26135
26136    #[test]
26137    fn gateway_api_key_request_carries_lower_camel_case_shape() {
26138        // Cross-axis invariant: a Kubernetes CRD schema field name is a
26139        // lowerCamelCase identifier per the K8s API conventions
26140        // (https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#naming-conventions —
26141        // "Field names should be lowercase camelCase") — first byte
26142        // ASCII-lowercase, rest ASCII-alphanumeric, no snake_case or
26143        // kebab-case or whitespace. Pinning the shape here means a
26144        // future rebrand on the canonical lift can't silently land a
26145        // malformed field-name discriminator (snake_case, kebab-case,
26146        // UpperCamelCase, empty) that the apiserver-side CRD schema
26147        // validator would reject far from the rebrand commit's source.
26148        // Peer to `gateway_api_key_attempts_carries_lower_camel_case_shape`
26149        // / `gateway_api_key_retry_carries_lower_camel_case_shape`
26150        // / `gateway_api_key_timeouts_carries_lower_camel_case_shape`
26151        // / `gateway_api_key_hostnames_carries_lower_camel_case_shape`
26152        // / `gateway_api_key_hostname_carries_lower_camel_case_shape`
26153        // / `gateway_api_key_listeners_carries_lower_camel_case_shape`
26154        // / `gateway_api_key_parent_refs_carries_lower_camel_case_shape`
26155        // / `gateway_api_key_backend_refs_carries_lower_camel_case_shape`
26156        // on the sibling per-Gateway-API-CRD-body-axis grammar-pin
26157        // surface — the lowerCamelCase K8s field-name grammar governs
26158        // every nested schema-field axis (including this per-rule
26159        // request-deadline-leaf-key), same convention.
26160        let v = GATEWAY_API_KEY_REQUEST;
26161        assert!(
26162            !v.is_empty(),
26163            "GATEWAY_API_KEY_REQUEST {v:?} must be non-empty per the K8s API \
26164             lowerCamelCase field-name grammar"
26165        );
26166        let first = v.chars().next().expect("non-empty");
26167        assert!(
26168            first.is_ascii_lowercase(),
26169            "GATEWAY_API_KEY_REQUEST {v:?} first byte {first:?} must be \
26170             ASCII-lowercase per the K8s API lowerCamelCase field-name \
26171             grammar (field names are always lowerCamelCase)"
26172        );
26173        assert!(
26174            v.chars().all(|c| c.is_ascii_alphanumeric()),
26175            "GATEWAY_API_KEY_REQUEST {v:?} must be ASCII-alphanumeric \
26176             throughout per the K8s API field-name grammar — no \
26177             snake_case, kebab-case, or whitespace bytes the apiserver-side \
26178             OpenAPI schema validator would reject"
26179        );
26180    }
26181
26182    #[test]
26183    fn default_namespace_is_a_valid_dns_1123_label() {
26184        // Cross-axis invariant: the default namespace lands as
26185        // `metadata.namespace` on every emitted K8s object across every
26186        // renderer, and the K8s apiserver enforces the DNS-1123 label
26187        // rule on every `metadata.namespace`. Pinning this here means
26188        // a future rebrand on the canonical `DEFAULT_NAMESPACE`
26189        // declaration can't silently land a value the apiserver
26190        // refuses at the *first* renderer to apply against a cluster,
26191        // far from the rebrand commit's source — the typed
26192        // [`is_dns_1123_label`] floor rejects it at caixa-core build
26193        // time on the canonical lift, before any renderer consumes
26194        // the value. Same trajectory as `:membros :caixa` /
26195        // `:placement :clusters` / `:contratos :de`/`:para` /
26196        // `:entrada :para` / `:placement :affinity` (dfd4902 — the
26197        // five typed-identifier axes on the Aplicacao surface that
26198        // already land on this same `is_dns_1123_label` floor at
26199        // their respective validate gates), now extended onto the
26200        // canonical-namespace-default axis the renderers share.
26201        assert!(
26202            is_dns_1123_label(DEFAULT_NAMESPACE).is_ok(),
26203            "DEFAULT_NAMESPACE {DEFAULT_NAMESPACE:?} must be a valid \
26204             DNS-1123 label — every K8s apiserver-side schema enforces \
26205             this rule on `metadata.namespace`"
26206        );
26207    }
26208
26209    #[test]
26210    fn helm_chart_api_version_pins_canonical_value() {
26211        // Pin the actual string so a typo in this lift can't silently
26212        // rebrand the Helm 3 chart-schema apiVersion the rendered
26213        // `lareira-<nome>` `Chart.yaml` document declares at its
26214        // top-level `apiVersion` axis. The string is part of the
26215        // Helm-side contract with the Helm 3 chart-schema parser:
26216        // `helm dependency build` / `helm lint` / `helm template`
26217        // all resolve the chart under the Helm 3 v2 schema (permitting
26218        // top-level `dependencies:`); a drifted value to the legacy
26219        // Helm 2 `"v1"` schema (the pre-Helm-3 chart schema every
26220        // upstream Helm-3-migration doc names) silently reroutes the
26221        // rendered Chart.yaml through the Helm 2 parser, where the
26222        // top-level `dependencies:` block is unknown and the chart's
26223        // dep on the `pleme-computeunit` library chart never resolves
26224        // — `helm dependency build` reports "no requirements found"
26225        // and every `helm template` / `helm install` emits an empty
26226        // release (no ComputeUnit / Service / ScaledObject resources
26227        // land) far from the source caixa.lisp / the renderer's
26228        // `build_chart_yaml` call site. Changing it is a coordinated
26229        // Helm 4 chart-schema migration alongside the upstream Helm
26230        // chart-schema deprecation cycle, not an incidental edit.
26231        // Peer to `flux_helmrelease_api_version_pins_canonical_value`
26232        // / `flux_gitrepository_api_version_pins_canonical_value` /
26233        // `flux_kustomization_api_version_pins_canonical_value` /
26234        // `gateway_api_api_version_pins_canonical_value` /
26235        // `cilium_api_version_pins_canonical_value` on the sibling
26236        // cluster-side-CRD-apiVersion-pin set — those pin the K8s
26237        // apiserver-side `(apiVersion, kind)` `RESTMapper` contract,
26238        // this one pins the Helm-side chart-schema-parser contract
26239        // that gates every rendered `lareira-<nome>` chart's
26240        // dependency resolution before any K8s resource lands.
26241        assert_eq!(HELM_CHART_API_VERSION, "v2");
26242    }
26243
26244    #[test]
26245    fn helm_chart_api_version_carries_helm_3_chart_schema_shape() {
26246        // Cross-axis invariant: the Helm 3 chart-schema apiVersion is
26247        // a bare `v<digit>` version label (unlike the K8s CRD
26248        // apiVersion — `<group>/<version>` — the sibling
26249        // FLUX_HELMRELEASE_API_VERSION / GATEWAY_API_API_VERSION /
26250        // CILIUM_API_VERSION lifts pin). The Helm-side chart-schema
26251        // grammar carries no group prefix at all — the value is
26252        // parsed as a plain schema-version discriminator against the
26253        // Helm binary's built-in schema table (Helm 2 recognizes
26254        // `"v1"`, Helm 3 recognizes both `"v1"` for legacy compat
26255        // and `"v2"` for its native schema). Pinning the shape here
26256        // means a future rebrand on the canonical lift can't silently
26257        // land a K8s-CRD-shaped `group/version` value (e.g. an
26258        // accidental copy-paste from the sibling FLUX / GATEWAY /
26259        // CILIUM constants) that the Helm chart-schema parser would
26260        // fail to recognize at `helm dependency build` /
26261        // `helm lint` / `helm template` time. The `v<digit>+`
26262        // invariant is the load-bearing Helm-side chart-schema
26263        // typed-discovery contract: a value the Helm binary's
26264        // chart-schema resolver consults to select the schema
26265        // parser that reads the rest of the document. Peer to
26266        // `flux_kind_helm_release_carries_upper_camel_case_shape`
26267        // (which pins the K8s `RESTMapper` kind-grammar shape) —
26268        // both close the "the shape of the lifted schema-version
26269        // discriminator is grammatical, not just a byte-equal string"
26270        // discipline at the lift site.
26271        let v = HELM_CHART_API_VERSION;
26272        assert!(
26273            !v.is_empty(),
26274            "HELM_CHART_API_VERSION {v:?} must be non-empty per the Helm \
26275             chart-schema apiVersion grammar"
26276        );
26277        assert!(
26278            !v.contains('/'),
26279            "HELM_CHART_API_VERSION {v:?} must not contain `/` — the Helm-side \
26280             chart-schema apiVersion is a bare `v<digit>` label with no group \
26281             prefix, unlike the K8s CRD `<group>/<version>` shape the sibling \
26282             FLUX_HELMRELEASE_API_VERSION / GATEWAY_API_API_VERSION / \
26283             CILIUM_API_VERSION lifts carry"
26284        );
26285        let bytes = v.as_bytes();
26286        assert_eq!(
26287            bytes[0], b'v',
26288            "HELM_CHART_API_VERSION {v:?} must start with `v` per the Helm \
26289             chart-schema apiVersion grammar (`v1` for the legacy schema, \
26290             `v2` for the Helm 3 schema — every accepted value the Helm \
26291             binary's chart-schema resolver knows carries the `v` prefix)"
26292        );
26293        assert!(
26294            bytes.len() >= 2,
26295            "HELM_CHART_API_VERSION {v:?} must be at least 2 bytes (`v` + \
26296             at least one digit) per the Helm chart-schema apiVersion \
26297             grammar"
26298        );
26299        assert!(
26300            bytes[1..].iter().all(u8::is_ascii_digit),
26301            "HELM_CHART_API_VERSION {v:?} bytes after the leading `v` must be \
26302             ASCII digits per the Helm chart-schema apiVersion grammar — \
26303             no dots, no hyphens, no whitespace, no non-digit bytes the \
26304             Helm binary's chart-schema resolver would reject"
26305        );
26306    }
26307
26308    #[test]
26309    fn helm_chart_type_application_pins_canonical_value() {
26310        // Pin the actual string so a typo in this lift can't silently
26311        // rebrand the Helm 3 chart-schema `type` field's canonical
26312        // `application` per-chart-kind discriminator scalar-value the
26313        // rendered `lareira-<nome>` chart's Chart.yaml `type:` axis
26314        // declares. The value is part of the cluster-side contract with
26315        // Helm's per-release install-shape dispatch loop — the Helm
26316        // chart-schema pins the per-chart-kind axis to the closed set
26317        // `{"application", "library"}` (see
26318        // https://helm.sh/docs/topics/charts/#chart-types), so a drifted
26319        // value (`"Application"` / `"APPLICATION"` / `"app"` /
26320        // `"workload"`) lands the rendered `lareira-<nome>` chart outside
26321        // the schema's admitted set, and Helm's chart-schema parser
26322        // silently treats the unrecognized value as the default
26323        // `application` shape (masking the schema violation with no
26324        // process-log drift-signal); worse, an accidental collapse onto
26325        // the sibling `"library"` shape lands `lareira-<nome>` in the
26326        // dependency-only install-shape Helm refuses to install directly
26327        // ("Error: library charts cannot be installed"), dropping every
26328        // per-Servico `helm install` / `helm upgrade` release cycle with
26329        // no field naming the chart-kind-drift root cause. Changing this
26330        // value is a coordinated Helm chart-schema promotion alongside
26331        // the upstream Helm project's per-schema deprecation cycle, not
26332        // an incidental edit. Peer to
26333        // `helm_chart_api_version_pins_canonical_value` /
26334        // `kube_protocol_tcp_pins_canonical_value` /
26335        // `gateway_api_protocol_http_pins_canonical_value` /
26336        // `cilium_auth_mode_required_pins_canonical_value` on the
26337        // sibling canonical-Helm-chart-schema-axis + canonical-cluster-
26338        // side-OpenAPI-schema-enum-value pin sets — pivots the
26339        // canonical-enum-value single-sourcing discipline from the K8s-
26340        // CR-side surfaces onto the Helm-chart-schema-enum-value axis
26341        // every rendered Chart.yaml carries at its per-chart-kind
26342        // discriminator field.
26343        assert_eq!(HELM_CHART_TYPE_APPLICATION, "application");
26344    }
26345
26346    #[test]
26347    fn helm_chart_type_application_carries_lowercase_shape() {
26348        // Cross-axis invariant: the Helm 3 chart-schema `type` field
26349        // admits the closed set `{"application", "library"}` — every
26350        // admitted value is all-ASCII-lowercase throughout per the
26351        // upstream Helm project's per-enum-value naming convention
26352        // (distinct from the sibling K8s-core `Protocol` OpenAPI schema
26353        // enum's all-ASCII-uppercase per-value convention the
26354        // `kube_protocol_tcp_carries_upper_case_shape` pin carries, and
26355        // distinct from the sibling Gateway-API v1 `PathMatchType`
26356        // OpenAPI schema enum's UpperCamelCase per-value convention the
26357        // `gateway_api_path_match_type_path_prefix_carries_upper_camel_case_shape`
26358        // pin carries — the three peer canonical-cluster-side-schema-
26359        // enum-value conventions do not collapse). Same all-ASCII-
26360        // lowercase shape as the sibling Cilium `MutualAuthenticationMode`
26361        // enum-values the peer `cilium_auth_mode_required_carries_lowercase_shape`
26362        // / `cilium_auth_mode_disabled_carries_lowercase_shape` pins
26363        // enshrine — the two peer canonical-cluster-side-schema-enum-
26364        // value all-lowercase conventions collapse on the shared byte-
26365        // shape convention Helm and Cilium happen to share (independent
26366        // upstream projects, coincidental convention agreement).
26367        //
26368        // Pinning the shape here means a future rebrand on the canonical
26369        // lift can't silently land a malformed per-chart-kind scalar
26370        // (uppercase `"APPLICATION"`, mixed-case `"Application"`, empty)
26371        // that the Helm chart-schema parser would silently treat as the
26372        // default `application` shape (masking the drift with no
26373        // process-log signal).
26374        let v = HELM_CHART_TYPE_APPLICATION;
26375        assert!(
26376            !v.is_empty(),
26377            "HELM_CHART_TYPE_APPLICATION {v:?} must be non-empty per the \
26378             Helm 3 chart-schema `type` field grammar"
26379        );
26380        assert!(
26381            v.chars().all(|c| c.is_ascii_lowercase()),
26382            "HELM_CHART_TYPE_APPLICATION {v:?} must be ASCII-lowercase \
26383             throughout per the Helm 3 chart-schema per-chart-kind \
26384             discriminator naming convention — no uppercase, mixed-case, \
26385             or whitespace bytes the Helm chart-schema parser would \
26386             silently treat as the default `application` shape (masking \
26387             the drift with no process-log signal)"
26388        );
26389    }
26390
26391    #[test]
26392    fn helm_chart_type_library_pins_canonical_value() {
26393        // Pin the sibling closed-set arm of the Helm 3 chart-schema
26394        // `type` field's admitted set `{"application", "library"}` (see
26395        // https://helm.sh/docs/topics/charts/#chart-types). A drift on
26396        // this const's value (an `"Library"` / `"LIBRARY"` /
26397        // `"library-chart"` / `"lib"` typo, an accidental collapse onto
26398        // the sibling [`HELM_CHART_TYPE_APPLICATION`] shape) would land
26399        // a future per-Aplicacao library-chart emitter — the trajectory
26400        // item the [`HELM_CHART_TYPE_APPLICATION`] docstring names as
26401        // the natural next consumer of this const — outside the Helm
26402        // chart-schema's admitted set, with the same silent-collapse-
26403        // onto-`application`-default failure mode the peer
26404        // [`HELM_CHART_TYPE_APPLICATION`] pin's docstring enumerates on
26405        // the sibling closed-set arm (Helm's chart-schema parser
26406        // silently treats an unrecognized `type:` value as the default
26407        // `application` shape, so the misdeclared library chart installs
26408        // as an application chart instead of surfacing the schema
26409        // violation). Peer of
26410        // `helm_chart_type_application_pins_canonical_value` on the
26411        // sibling closed-set arm — the two pins together enshrine the
26412        // full closed set at the substrate-side canonical surface, and
26413        // the paired
26414        // `helm_chart_type_application_and_library_are_distinct` pin
26415        // (below) enforces the two arms never accidentally converge on
26416        // the same byte-shape.
26417        assert_eq!(HELM_CHART_TYPE_LIBRARY, "library");
26418    }
26419
26420    #[test]
26421    fn helm_chart_type_library_carries_lowercase_shape() {
26422        // Cross-axis invariant: the Helm 3 chart-schema `type` field
26423        // admits the closed set `{"application", "library"}` — every
26424        // admitted value is all-ASCII-lowercase throughout per the
26425        // upstream Helm project's per-enum-value naming convention.
26426        // Same all-ASCII-lowercase shape the peer
26427        // `helm_chart_type_application_carries_lowercase_shape` pin
26428        // enshrines on the sibling closed-set arm — the two pins
26429        // together enforce the shape-convention across the full
26430        // canonical-Helm-chart-schema-per-chart-kind-discriminator
26431        // closed set.
26432        //
26433        // Pinning the shape here means a future rebrand on the canonical
26434        // lift can't silently land a malformed per-chart-kind scalar
26435        // (uppercase `"LIBRARY"`, mixed-case `"Library"`, empty) that
26436        // the Helm chart-schema parser would silently treat as the
26437        // default `application` shape (masking the drift with no
26438        // process-log signal, and installing the misdeclared library
26439        // chart as an application chart instead of surfacing the
26440        // schema violation at chart-consumption time).
26441        let v = HELM_CHART_TYPE_LIBRARY;
26442        assert!(
26443            !v.is_empty(),
26444            "HELM_CHART_TYPE_LIBRARY {v:?} must be non-empty per the \
26445             Helm 3 chart-schema `type` field grammar"
26446        );
26447        assert!(
26448            v.chars().all(|c| c.is_ascii_lowercase()),
26449            "HELM_CHART_TYPE_LIBRARY {v:?} must be ASCII-lowercase \
26450             throughout per the Helm 3 chart-schema per-chart-kind \
26451             discriminator naming convention — no uppercase, mixed-case, \
26452             or whitespace bytes the Helm chart-schema parser would \
26453             silently treat as the default `application` shape (masking \
26454             the drift with no process-log signal)"
26455        );
26456    }
26457
26458    #[test]
26459    fn helm_chart_type_application_and_library_are_distinct() {
26460        // Structural distinctness invariant on the closed-set pair the
26461        // Helm 3 chart-schema `type` field admits (`{"application",
26462        // "library"}`). The two arms name distinct per-chart-kind
26463        // install shapes at the substrate-side Helm dispatch — an
26464        // `application`-typed chart installs into a namespace as a
26465        // workload while a `library`-typed chart is dependency-only
26466        // and Helm refuses to install it directly ("Error: library
26467        // charts cannot be installed") — so a future rebrand that
26468        // accidentally collapsed the two consts onto the same
26469        // byte-shape would land every consumer of one arm on the
26470        // sibling's install semantic by construction: a rendered
26471        // `lareira-<nome>` (application) chart that silently emitted
26472        // `type: library` would drop every per-Servico
26473        // `helm install` / `helm upgrade` release cycle with no field
26474        // naming the chart-kind-drift root cause, and (symmetrically)
26475        // a future per-Aplicacao library chart emitting
26476        // `type: application` would be install-able as a workload
26477        // when the substrate's install-shape dispatch expects it to
26478        // fail with the library-charts-cannot-be-installed diagnostic.
26479        // Pinning the distinctness here means a hypothetical future
26480        // edit that accidentally converges the two arms (a copy-paste
26481        // rebrand at one lift that stops at the peer const declaration,
26482        // a substrate-wide vocabulary shift that lands one arm without
26483        // its paired peer) surfaces at caixa-core build time rather
26484        // than as a chart-install-shape drift far from the source
26485        // commit. Same "closed-set arms are byte-distinct by
26486        // construction" discipline the peer
26487        // [`crate::CILIUM_AUTH_MODE_REQUIRED`] /
26488        // [`crate::CILIUM_AUTH_MODE_DISABLED`] pair carries on the
26489        // sibling two-arm Cilium `MutualAuthenticationMode` OpenAPI
26490        // enum closed set.
26491        assert_ne!(
26492            HELM_CHART_TYPE_APPLICATION, HELM_CHART_TYPE_LIBRARY,
26493            "HELM_CHART_TYPE_APPLICATION ({HELM_CHART_TYPE_APPLICATION:?}) and \
26494             HELM_CHART_TYPE_LIBRARY ({HELM_CHART_TYPE_LIBRARY:?}) must remain \
26495             byte-distinct — the two arms name the two install shapes of the \
26496             Helm 3 chart-schema `type` field's closed set {{\"application\", \
26497             \"library\"}} and every substrate-side consumer that dispatches \
26498             on the per-chart-kind axis relies on the two byte-shapes \
26499             distinguishing the workload-install-shape arm from the \
26500             dependency-only-install-shape arm"
26501        );
26502    }
26503
26504    #[test]
26505    fn helm_chart_key_api_version_pins_canonical_value() {
26506        // Pin the actual byte-string so a typo in this lift can't
26507        // silently rebrand the Helm 3 `Chart.yaml` top-level chart-
26508        // schema-apiVersion YAML axis-key the rendered `lareira-<nome>`
26509        // chart declares. The string is part of the substrate-side
26510        // contract with Helm's chart-schema parser at
26511        // `helm dependency build` / `helm lint` / `helm template` /
26512        // `helm install` time: the parser looks up the per-chart
26513        // chart-schema-apiVersion scalar under exactly this top-level
26514        // YAML key (Helm's chart-schema treats a missing `apiVersion:`
26515        // top-level scalar as an "apiVersion is required" hard error,
26516        // and Helm 3's chart-schema-version-router silently defaults
26517        // an unrecognized top-level apiVersion-carrier key to Helm 2
26518        // parsing shape). A drift on this const's value (an accidental
26519        // collapse onto `"ApiVersion"` / `"apiversion"` /
26520        // `"schemaVersion"` / the empty string) would silently reroute
26521        // the rendered `Chart.yaml` through the wrong chart-schema
26522        // parser at `helm dependency build` / `helm lint` /
26523        // `helm template` time. Peer to
26524        // `helm_chart_api_version_pins_canonical_value` on the sibling
26525        // axis-value canonical pin — completes the per-Chart.yaml
26526        // chart-schema-apiVersion axis's `(key, value)` canonical-pin
26527        // pair at the substrate.
26528        assert_eq!(HELM_CHART_KEY_API_VERSION, "apiVersion");
26529    }
26530
26531    #[test]
26532    fn helm_chart_key_api_version_matches_kube_key_api_version() {
26533        // Load-bearing byte-shape coincidence between the Helm 3
26534        // `Chart.yaml` top-level chart-schema-apiVersion YAML axis-key
26535        // ([`HELM_CHART_KEY_API_VERSION`]) and the K8s-CR top-level
26536        // per-CR schema-apiVersion YAML axis-key ([`KUBE_KEY_API_VERSION`])
26537        // — Helm inherits the K8s CR top-level shape verbatim (see
26538        // https://helm.sh/docs/topics/charts/#the-chartyaml-file), so
26539        // every consumer that navigates a Chart.yaml top-level mapping
26540        // by the schema-apiVersion key and every consumer that
26541        // navigates a K8s CR top-level mapping by the schema-apiVersion
26542        // key both read the byte-identical `"apiVersion"` key. The two
26543        // axes are structurally-independent schema surfaces (the Helm 3
26544        // chart-schema top-level shape vs. the K8s apiserver-side CR
26545        // top-level shape), so the substrate carries two distinct
26546        // `pub const` symbols; this pin makes the byte-shape
26547        // coincidence load-bearing rather than accidental so a future
26548        // K8s-side rebrand at [`KUBE_KEY_API_VERSION`] (or a Helm-side
26549        // rebrand at [`HELM_CHART_KEY_API_VERSION`]) that dropped the
26550        // byte-identity would fail the pin at substrate-build time
26551        // rather than as a silent Helm-chart-schema-parser rejection
26552        // at `helm lint` / `helm template` time far from the drift
26553        // site. Complementary to the sibling
26554        // [`helm_chart_key_type_is_byte_distinct_from_kube_key_kind`]
26555        // pin — that peer asserts the per-chart-kind discriminator key
26556        // pair is byte-distinct across the two schema surfaces (the
26557        // Chart.yaml `type:` axis vs. the K8s CR `kind:` axis), and
26558        // this pin asserts the per-schema-apiVersion axis-key pair is
26559        // byte-identical across the two schema surfaces; together the
26560        // two pins cover the full independence-map of the top-level
26561        // discriminator axes at the two schema surfaces.
26562        assert_eq!(
26563            HELM_CHART_KEY_API_VERSION, KUBE_KEY_API_VERSION,
26564            "HELM_CHART_KEY_API_VERSION ({HELM_CHART_KEY_API_VERSION:?}) \
26565             must remain byte-identical to KUBE_KEY_API_VERSION \
26566             ({KUBE_KEY_API_VERSION:?}) — Helm 3 inherits the K8s CR \
26567             top-level schema-apiVersion YAML-axis-key byte-shape \
26568             verbatim, and every downstream consumer that navigates a \
26569             `Chart.yaml` / K8s CR top-level mapping by the schema-\
26570             apiVersion key reads the byte-identical `\"apiVersion\"` \
26571             key; a drift on either side silently reroutes the \
26572             consumer through a schema-parser rejection far from the \
26573             drift site"
26574        );
26575    }
26576
26577    #[test]
26578    fn helm_chart_key_type_pins_canonical_value() {
26579        // Pin the actual byte-string so a typo in this lift can't silently
26580        // rebrand the Helm 3 `Chart.yaml` top-level per-chart-kind
26581        // discriminator YAML axis-key the rendered `lareira-<nome>` chart
26582        // declares. The string is part of the substrate-side contract with
26583        // Helm's chart-schema parser at `helm dependency build` /
26584        // `helm lint` / `helm template` / `helm install` time: the parser
26585        // looks up the per-chart-kind discriminator scalar under exactly
26586        // this top-level YAML key, and a drift on this const's value
26587        // (an accidental collapse onto `"Type"` / `"chartType"` /
26588        // `"kind"`, or the empty string) would silently reroute the
26589        // rendered `Chart.yaml` through the schema-shape-defaulting arm
26590        // of Helm's parser (unknown top-level keys default the
26591        // per-chart-kind axis to `application` with no process-log
26592        // signal). Peer to
26593        // `helm_chart_type_application_pins_canonical_value` /
26594        // `helm_chart_type_library_pins_canonical_value` on the sibling
26595        // axis-value canonical pin pair — completes the per-Chart.yaml
26596        // per-chart-kind discriminator axis's `(key, value-set)`
26597        // canonical-pin trio at the substrate.
26598        assert_eq!(HELM_CHART_KEY_TYPE, "type");
26599    }
26600
26601    #[test]
26602    fn helm_chart_key_type_is_byte_distinct_from_kube_key_kind() {
26603        // Structural distinctness invariant: the Helm 3 `Chart.yaml`
26604        // top-level per-chart-kind YAML axis-key
26605        // ([`HELM_CHART_KEY_TYPE`]) and the K8s CR top-level per-CRD
26606        // kind-discriminator YAML axis-key ([`KUBE_KEY_KIND`]) name
26607        // two structurally-independent axes at two structurally-
26608        // independent schema surfaces — the Helm-side chart-schema
26609        // top-level shape and the K8s-apiserver-side CR top-level
26610        // shape — and every substrate-side renderer that emits or
26611        // navigates a `Chart.yaml` vs. a K8s CR YAML relies on the
26612        // two byte-shapes distinguishing the two schema-surfaces at
26613        // its top-level mapping-key resolution. A hypothetical future
26614        // rebrand that accidentally aliased [`HELM_CHART_KEY_TYPE`]
26615        // at [`KUBE_KEY_KIND`]'s canonical would collapse the
26616        // per-Chart.yaml per-chart-kind discriminator axis onto the
26617        // K8s-CR per-CRD kind-discriminator axis at every consumer,
26618        // and Helm's chart-schema parser would silently drop the
26619        // rebranded key (top-level `kind:` is not part of the Helm 3
26620        // chart-schema's admitted set — the parser silently ignores
26621        // it, defaulting the per-chart-kind axis to `application`
26622        // with no process-log signal). Same "byte-distinct axis-keys
26623        // at structurally-independent schema surfaces" discipline the
26624        // peer [`CILIUM_KEY_PATH`] / [`GATEWAY_API_KEY_PATH`]
26625        // (ef6114f / 9f45aa4) pair carries on the sibling Cilium-CRD-
26626        // vs.-Gateway-API-per-HTTPRouteMatch path-matcher axis
26627        // independence — extends the discipline from the two K8s-CR-
26628        // side path-matcher schemas onto the Helm-side vs. K8s-side
26629        // top-level discriminator-key axis pair.
26630        assert_ne!(
26631            HELM_CHART_KEY_TYPE, KUBE_KEY_KIND,
26632            "HELM_CHART_KEY_TYPE ({HELM_CHART_KEY_TYPE:?}) and \
26633             KUBE_KEY_KIND ({KUBE_KEY_KIND:?}) name the top-level \
26634             discriminator keys of two structurally-independent schema \
26635             surfaces (the Helm 3 chart-schema and the K8s apiserver-side \
26636             CR schema) and must remain byte-distinct — a collapse \
26637             silently reroutes the per-Chart.yaml per-chart-kind axis \
26638             through the K8s-CR-shape-defaulting arm of Helm's parser"
26639        );
26640    }
26641
26642    #[test]
26643    fn helm_chart_key_app_version_pins_canonical_value() {
26644        // Pin the actual byte-string so a typo in this lift can't silently
26645        // rebrand the Helm 3 `Chart.yaml` top-level per-chart-app-version
26646        // YAML axis-key the rendered `lareira-<nome>` chart declares.
26647        // The string is part of the substrate-side contract with Helm's
26648        // chart-schema parser + every downstream chart-consumer that
26649        // routes the underlying-application-version display onto the
26650        // rendered chart's per-app-version field (Artifact Hub's per-
26651        // chart-search index, `helm search` / `helm show chart` operator
26652        // surfaces, the OCI-artifact-labels emitter every chart-publish
26653        // pipeline exports). A drift on this const's value (`"AppVersion"`
26654        // / `"applicationVersion"` / `"appversion"` / the empty string)
26655        // would silently drop the underlying-application-version field
26656        // from the parsed chart-metadata shape at every downstream
26657        // consumer, with no process-log signal at the substrate-side
26658        // emitter site. The `appVersion:` camelCase byte-shape is the
26659        // load-bearing Helm chart-schema per-app-version YAML axis-key
26660        // grammar the upstream Helm project pins. Peer to
26661        // `helm_chart_key_type_pins_canonical_value` on the sibling
26662        // per-Chart.yaml top-level YAML axis-key canonical pin surface —
26663        // completes the per-Chart.yaml top-level YAML axis-key
26664        // canonical-pin trio at the substrate for the three serde-
26665        // rename-literal-only axes on [`caixa_helm::ChartYaml`] (the
26666        // third top-level axis-key `apiVersion` lands under the peer
26667        // [`HELM_CHART_KEY_API_VERSION`] pin whose byte-shape coincides
26668        // with [`KUBE_KEY_API_VERSION`] by Helm's design decision to
26669        // inherit the K8s CR top-level shape verbatim — the paired
26670        // `helm_chart_key_api_version_matches_kube_key_api_version`
26671        // pin makes the coincidence load-bearing rather than
26672        // accidental).
26673        assert_eq!(HELM_CHART_KEY_APP_VERSION, "appVersion");
26674    }
26675
26676    #[test]
26677    fn helm_chart_key_app_version_is_byte_distinct_from_helm_chart_key_version() {
26678        // Structural distinctness invariant on the per-Chart.yaml top-
26679        // level version-axis-key pair. The Helm 3 chart-schema pins two
26680        // structurally-distinct version YAML axis-keys at the top-level
26681        // of every `Chart.yaml`:
26682        //
26683        //   - `version:` — the chart's own SemVer (incremented per
26684        //     release of the chart itself)
26685        //   - `appVersion:` — the underlying application's version
26686        //     (the version the containerized workload the chart
26687        //     installs advertises)
26688        //
26689        // At the caixa-helm renderer both YAML axes today draw from the
26690        // caixa's `:versao` at `build_chart_yaml` (a caixa's per-caixa
26691        // BLAKE3-closure identity binds chart + wasm-binary at exactly
26692        // one release axis), but the Helm 3 chart-schema pins the two
26693        // top-level YAML keys distinctly regardless — every downstream
26694        // Helm-consumer (Artifact Hub's per-chart index, `helm search` /
26695        // `helm show chart` surfaces) routes the two version-axis
26696        // scalars onto distinct display fields. A hypothetical future
26697        // rebrand that accidentally aliased [`HELM_CHART_KEY_APP_VERSION`]
26698        // at the sibling per-Chart.yaml top-level `version:` key
26699        // (`"version"`) would collapse the two YAML axes at the
26700        // renderer's ChartYaml serialization, and Helm's chart-schema
26701        // parser would silently read the app-version scalar under the
26702        // chart-own-SemVer axis (the last `version:` key wins in
26703        // `serde_yaml`'s emitted mapping under this drift), overwriting
26704        // the chart's own SemVer at every downstream chart-consumer.
26705        // Same "byte-distinct version-axis keys at the same schema
26706        // surface" discipline the peer [`FLEET_PROGRAMS_KEY_VERSAO`] /
26707        // [`FLEET_PROGRAMS_KEY_NAME`] pair carries on the sibling
26708        // per-fleet-programs-entry axis pair — extends the discipline
26709        // from the per-fleet-programs-entry key-pair onto the per-
26710        // Chart.yaml top-level version-axis-key pair.
26711        assert_ne!(
26712            HELM_CHART_KEY_APP_VERSION, "version",
26713            "HELM_CHART_KEY_APP_VERSION ({HELM_CHART_KEY_APP_VERSION:?}) \
26714             must remain byte-distinct from the sibling per-Chart.yaml \
26715             top-level chart-own-SemVer `version:` key — a collapse \
26716             silently overwrites the chart's own SemVer at every \
26717             downstream Helm chart-consumer"
26718        );
26719    }
26720
26721    #[test]
26722    fn helm_chart_key_dependencies_pins_canonical_value() {
26723        // Pin the actual byte-string so a typo in this lift can't silently
26724        // rebrand the Helm 3 `Chart.yaml` top-level per-chart dependency-
26725        // list YAML axis-key the rendered `lareira-<nome>` chart declares.
26726        // The string is part of the substrate-side contract with Helm's
26727        // chart-schema parser — every rendered chart's `dependencies:`
26728        // list-container mounts under this exact byte-shape, and Helm's
26729        // per-dep resolver at `helm dependency build` / `helm dependency
26730        // update` time consumes the per-entry sub-mapping tetrad only if
26731        // the top-level list-container key matches this canonical shape.
26732        // A drift on this const's value (`"Dependencies"` / `"deps"` /
26733        // `"chartDependencies"` / `"depends"` / the empty string) would
26734        // silently drop the entire per-chart dep list from the parsed
26735        // chart-metadata shape, and every rendered `lareira-<nome>`
26736        // chart's install would fail with `template: no template ...
26737        // associated with template ...` far from the drift site with
26738        // no field naming the top-level-list-key-drift root cause. Peer
26739        // to [`helm_chart_key_type_pins_canonical_value`] /
26740        // [`helm_chart_key_app_version_pins_canonical_value`] /
26741        // [`helm_chart_key_api_version_pins_canonical_value`] on the
26742        // sibling per-Chart.yaml top-level YAML axis-key canonical-pin
26743        // surface — extends the per-Chart.yaml top-level YAML axis-key
26744        // canonical-pin trio those pins established onto the fourth
26745        // top-level axis-key at the substrate, the parent list-container
26746        // whose already-lifted per-`dependencies[]`-entry sub-mapping
26747        // tetrad ([`HELM_CHART_DEPENDENCY_KEY_NAME`] /
26748        // [`HELM_CHART_DEPENDENCY_KEY_VERSION`] /
26749        // [`HELM_CHART_DEPENDENCY_KEY_REPOSITORY`] /
26750        // [`HELM_CHART_DEPENDENCY_KEY_ALIAS`]) mounts one level down.
26751        assert_eq!(HELM_CHART_KEY_DEPENDENCIES, "dependencies");
26752    }
26753
26754    #[test]
26755    fn helm_chart_key_dependencies_is_byte_distinct_from_per_dep_sub_mapping_tetrad() {
26756        // Structural distinctness invariant on the per-Chart.yaml
26757        // `dependencies:` parent list-container axis-key vs. the four
26758        // already-lifted per-entry sub-mapping keys mounted one level
26759        // down. The parent+children pair spans two schema-nested YAML
26760        // levels — the top-level `dependencies:` list-container and
26761        // the per-entry sub-mapping `{name, version, repository,
26762        // alias}` — and Helm's chart-schema parser navigates them as
26763        // two structurally-independent axes: a collapse of the parent
26764        // axis-key onto any child (e.g. an accidental future rebrand
26765        // that renamed the [`HELM_CHART_KEY_DEPENDENCIES`] value to
26766        // `"name"` or `"version"`) would either drop the entire per-
26767        // chart dep list at the top-level parse (the child scalar
26768        // silently masks the parent list-container the schema expects)
26769        // or read the top-level list under a scalar-shaped axis-key
26770        // and reject the chart at `helm lint` with a shape mismatch
26771        // far from the drift site. Same "parent list-container
26772        // axis-key must remain byte-distinct from every child sub-
26773        // mapping axis-key" discipline the peer
26774        // [`SUPERVISOR_KEY_CHILDREN`] parent axis-key already carries
26775        // against the sibling [`SUPERVISOR_CHILD_KEY_CAIXA`] /
26776        // [`SUPERVISOR_CHILD_KEY_VERSAO`] / [`SUPERVISOR_CHILD_KEY_RESTART`]
26777        // per-entry sub-mapping triad on the M2 typed
26778        // `:supervisor :children` surface — extends the discipline onto
26779        // the Helm 3 `Chart.yaml` per-chart-dependency-list surface.
26780        for child in [
26781            HELM_CHART_DEPENDENCY_KEY_NAME,
26782            HELM_CHART_DEPENDENCY_KEY_VERSION,
26783            HELM_CHART_DEPENDENCY_KEY_REPOSITORY,
26784            HELM_CHART_DEPENDENCY_KEY_ALIAS,
26785        ] {
26786            assert_ne!(
26787                HELM_CHART_KEY_DEPENDENCIES, child,
26788                "HELM_CHART_KEY_DEPENDENCIES \
26789                 ({HELM_CHART_KEY_DEPENDENCIES:?}) must remain \
26790                 byte-distinct from every per-`dependencies[]`-entry \
26791                 sub-mapping key ({child:?}) — a collapse silently \
26792                 orphans the parent list-container at `helm lint` / \
26793                 `helm dependency build` time"
26794            );
26795        }
26796    }
26797
26798    #[test]
26799    fn helm_chart_dependency_key_tetrad_pins_canonical_values() {
26800        // Byte-string pin on the per-`dependencies[]`-entry sub-mapping
26801        // YAML axis-key tetrad the Helm 3 chart-schema pins for every
26802        // per-dep entry the substrate emits under the top-level
26803        // `dependencies:` list at every rendered `lareira-<nome>`
26804        // Chart.yaml. The four axis-keys name the four load-bearing
26805        // per-dep sub-mapping fields Helm's per-dep resolver consumes
26806        // at `helm dependency build` / `helm dependency update` time:
26807        // `name` (the Helm-registry chart name), `version` (the SemVer-
26808        // range constraint), `repository` (the registry URL to fetch
26809        // from), and `alias` (the per-dep values wrap-key override).
26810        // A drift on any const's value (a typo on this lift, a case
26811        // flip to `"Name"` / `"Version"` / `"Repository"` / `"Alias"`,
26812        // an accidental collapse onto a sibling axis-key) would
26813        // silently rebrand the wire key at the `caixa_helm::ChartYaml`
26814        // emitter site — Helm's chart-schema parser silently drops
26815        // the drifted per-dep sub-mapping field, and the per-dep
26816        // resolver falls back to the parsed-shape defaults
26817        // (`""` / wildcard `*` / "no repository defined") at
26818        // `helm dependency build` time far from the drift site. Peer
26819        // to [`supervisor_child_key_tetrad_pins_canonical_values`] on
26820        // the sibling per-`:children` sub-mapping tetrad (ef912df) and
26821        // [`entrada_key_tetrad_pins_canonical_values`] on the sibling
26822        // per-`:entrada` sub-mapping tetrad (a3d6162).
26823        assert_eq!(HELM_CHART_DEPENDENCY_KEY_NAME, "name");
26824        assert_eq!(HELM_CHART_DEPENDENCY_KEY_VERSION, "version");
26825        assert_eq!(HELM_CHART_DEPENDENCY_KEY_REPOSITORY, "repository");
26826        assert_eq!(HELM_CHART_DEPENDENCY_KEY_ALIAS, "alias");
26827    }
26828
26829    #[test]
26830    fn helm_chart_dependency_key_name_matches_kube_key_name() {
26831        // Load-bearing byte-shape coincidence between the Helm 3
26832        // Chart.yaml per-`dependencies[]`-entry sub-mapping name key
26833        // ([`HELM_CHART_DEPENDENCY_KEY_NAME`]) and the K8s CR
26834        // per-`metadata` sub-mapping name key ([`KUBE_KEY_NAME`]) —
26835        // Helm inherits the K8s CR body-key vocabulary at every schema
26836        // surface it consumes (chart-metadata top-level, per-CR
26837        // install-payload, per-dep dependency-list). The two axes are
26838        // structurally-independent schema surfaces (the Helm 3
26839        // chart-schema per-dep entry vs. the K8s apiserver-side CR
26840        // metadata block) whose byte-shapes happen to coincide today;
26841        // this pin makes the byte-shape coincidence load-bearing
26842        // rather than accidental so a future K8s-side rebrand at
26843        // [`KUBE_KEY_NAME`] (or a Helm-side rebrand at
26844        // [`HELM_CHART_DEPENDENCY_KEY_NAME`]) that dropped the
26845        // byte-identity would fail the pin at substrate-build time
26846        // rather than as a silent Helm-per-dep-resolver drop at
26847        // `helm dependency build` time far from the drift site. Same
26848        // discipline as the peer
26849        // [`helm_chart_key_api_version_matches_kube_key_api_version`]
26850        // pin on the sibling top-level chart-schema-apiVersion axis
26851        // (cc44e4b) — extends the axis-key byte-identity coincidence
26852        // discipline from the per-Chart.yaml top-level shape onto the
26853        // per-`dependencies[]`-entry sub-mapping shape.
26854        assert_eq!(
26855            HELM_CHART_DEPENDENCY_KEY_NAME, KUBE_KEY_NAME,
26856            "HELM_CHART_DEPENDENCY_KEY_NAME ({HELM_CHART_DEPENDENCY_KEY_NAME:?}) \
26857             must remain byte-identical to KUBE_KEY_NAME ({KUBE_KEY_NAME:?}) — \
26858             Helm 3 inherits the K8s CR body-key vocabulary at every schema \
26859             surface, and every downstream consumer that navigates a per-dep \
26860             sub-mapping / a K8s CR metadata block by the `name` key reads the \
26861             byte-identical `\"name\"` key; a drift on either side silently \
26862             reroutes the consumer through a schema-parser drop far from the \
26863             drift site"
26864        );
26865    }
26866
26867    #[test]
26868    fn helm_chart_readme_filename_pins_canonical_value() {
26869        // Pin the actual byte-string so a typo on the canonical lift
26870        // can't silently rebrand the third leg of the per-`lareira-<nome>`
26871        // chart-directory `{Chart.yaml, values.yaml, README.md}`
26872        // canonical-per-chart-directory-filename axis triple. Peer to
26873        // the sibling
26874        // [`HELM_CHART_YAML_FILENAME`] / [`HELM_VALUES_YAML_FILENAME`]
26875        // canonical filename axes — the two schema-load-bearing halves
26876        // of the triple the sibling
26877        // [`HELM_VALUES_YAML_FILENAME`] docstring's closing paragraph
26878        // explicitly names as the pair that needed the third-leg
26879        // (`README.md`) filename half to close the discipline across
26880        // every `ChartFile` the [`caixa_helm::render_chart_for_servico`]
26881        // emitter's `ChartDir::files` vec carries. A drifted per-chart
26882        // readme filename value would surface downstream as GitHub /
26883        // Artifact Hub / any per-chart README-surfacing UI silently
26884        // falling back to "no README available" for the rendered
26885        // `lareira-<nome>` chart — the chart lists with no per-chart
26886        // elevator pitch or install instructions far from the drift
26887        // commit's source, with no field naming the readme-filename-
26888        // drift root cause. Same pin discipline as the peer
26889        // canonical-Helm-per-chart-directory-filename axes.
26890        assert_eq!(HELM_CHART_README_FILENAME, "README.md");
26891    }
26892
26893    #[test]
26894    fn helm_chart_readme_filename_carries_readme_dot_md_shape() {
26895        // Cross-axis invariant: the per-`lareira-<nome>`-chart-directory
26896        // human-facing readme filename carries the `.md` Markdown
26897        // extension the [`caixa_helm::build_readme`] emitter's Markdown-
26898        // shaped body targets — a drift to `.txt` / `.rst` /
26899        // extensionless / a per-fork rename would silently reroute the
26900        // rendered readme through a downstream tool that reads by
26901        // extension for its Markdown renderer (GitHub's per-repo README
26902        // surfacer, Artifact Hub's per-chart README surfacer, every
26903        // per-chart-directory `find . -name README.md` navigator any
26904        // downstream tooling might use). Peer to the sibling
26905        // [`HELM_CHART_YAML_FILENAME`] / [`HELM_VALUES_YAML_FILENAME`]
26906        // schema-load-bearing filename halves — the two YAML halves
26907        // carry the `.yaml` extension per Helm's per-chart-schema
26908        // convention; the readme half carries the `.md` extension per
26909        // the substrate's per-chart human-facing convention. Distinct
26910        // per-half schema conventions do not collapse on the shared
26911        // `<name>.<ext>` shape gate.
26912        let v = HELM_CHART_README_FILENAME;
26913        assert!(
26914            !v.is_empty(),
26915            "HELM_CHART_README_FILENAME {v:?} must be non-empty per the \
26916             per-`lareira-<nome>`-chart-directory readme-file axis"
26917        );
26918        assert!(
26919            v.ends_with(".md"),
26920            "HELM_CHART_README_FILENAME {v:?} must carry the `.md` \
26921             Markdown extension per the substrate's per-chart human-\
26922             facing readme convention — a drifted extension (`.txt` / \
26923             `.rst` / extensionless) would silently reroute downstream \
26924             tooling's Markdown renderer (GitHub's per-repo README \
26925             surfacer, Artifact Hub's per-chart README surfacer) to a \
26926             non-Markdown fallback path"
26927        );
26928    }
26929
26930    // ── lareira-<nome> chart-name prefix lift ──────────────────────
26931    //
26932    // The lift pins the substrate-wide `lareira-` chart-name prefix
26933    // as the single source of truth every per-Servico renderer
26934    // (caixa-helm, caixa-flux, caixa-tatara) reaches for, peer to the
26935    // [`DEFAULT_NAMESPACE`] (a085b26) lift on the canonical-namespace
26936    // axis. Pinning the prefix value, the helper's
26937    // construction-shape, and the DNS-1123-label round-trip for the
26938    // canonical-fixture input forms the structural floor every future
26939    // renderer consumer inherits by construction.
26940
26941    #[test]
26942    fn lareira_chart_name_prefix_pins_canonical_value() {
26943        // Pin the actual string value so a typo on the canonical lift
26944        // can't silently rebrand the substrate's per-Servico Helm chart
26945        // namespace. The string is part of the contract with the OCI
26946        // chart-publishing pipeline (`oci://<registry>/lareira-<nome>`),
26947        // the per-cluster HelmRelease `chart:` field (which Flux
26948        // resolves through the OCI ref), and the historical
26949        // `pleme-io/helmworks/charts/lareira-<name>/` source tree
26950        // layout (caixa-helm/src/lib.rs:7); changing it is a
26951        // coordinated multi-repo migration, not an incidental edit.
26952        // Peer to `default_namespace_pins_canonical_value` on the
26953        // canonical-string-value-pin axis for the
26954        // `DEFAULT_NAMESPACE` constant.
26955        assert_eq!(LAREIRA_CHART_NAME_PREFIX, "lareira-");
26956    }
26957
26958    #[test]
26959    fn lareira_chart_name_composes_prefix_and_nome() {
26960        // Pin the helper's construction shape — the chart name is the
26961        // prefix concatenated with the caixa's `:nome` verbatim, with
26962        // no intermediate hyphen, no path separator, no trimming. Pin
26963        // the canonical hello-rio fixture (the in-tree
26964        // `caixa-helm` test fixture at caixa-helm/src/lib.rs:431
26965        // already asserts `dir.name == "lareira-hello-rio"`, which
26966        // this helper now derives) and a peer fixture
26967        // (`checkout-aplicacao` member) to sweep the typical author
26968        // surface.
26969        assert_eq!(lareira_chart_name("hello-rio"), "lareira-hello-rio");
26970        assert_eq!(lareira_chart_name("cart"), "lareira-cart");
26971        assert_eq!(lareira_chart_name("worker"), "lareira-worker");
26972    }
26973
26974    #[test]
26975    fn lareira_chart_name_starts_with_prefix() {
26976        // Cross-axis invariant: every output of the helper begins with
26977        // the lifted prefix verbatim — a future refactor that
26978        // accidentally introduced a different prefix-application
26979        // shape (e.g. `format!("{nome}-lareira")` transposition, or a
26980        // `to_uppercase()` case fold) would surface here. The
26981        // structural pin holds for the empty `:nome` shape too
26982        // (a value `validate_nome` rejects upstream, but the helper
26983        // itself imposes no shape on the input).
26984        for nome in ["hello-rio", "cart", "worker", "a", ""] {
26985            let chart = lareira_chart_name(nome);
26986            assert!(
26987                chart.starts_with(LAREIRA_CHART_NAME_PREFIX),
26988                "lareira_chart_name({nome:?}) = {chart:?} must start with the lifted prefix \
26989                 {LAREIRA_CHART_NAME_PREFIX:?}"
26990            );
26991        }
26992    }
26993
26994    #[test]
26995    fn lareira_chart_name_round_trips_through_dns_1123_for_validated_nome() {
26996        // Cross-axis invariant: every `:nome` past
26997        // [`Caixa::validate_nome`] (6c992f8) is a valid DNS-1123 label,
26998        // and the prepended `lareira-` segment is itself a valid
26999        // DNS-1123 label prefix (lowercase ASCII + hyphen with a
27000        // terminating-hyphen continuation). The composition therefore
27001        // round-trips through [`is_dns_1123_label`] for every
27002        // `:nome` whose joint length with the prefix stays ≤ 63 bytes
27003        // (the DNS-1123 label cap). The canonical author surface sits
27004        // far below that cap (the in-tree fixtures range from
27005        // `"a"` = 9-byte chart name to `"checkout"` = 16 bytes, with
27006        // the cap admitting up to 55-byte `:nome` values). Pin the
27007        // round-trip for the canonical-fixture set so a future renderer
27008        // that lands the helper's output verbatim as a K8s
27009        // `metadata.name` (caixa-helm's `ChartDir.name`,
27010        // caixa-flux's HelmRelease `chart:` field, caixa-tatara's
27011        // `release_name`) inherits the apiserver-valid floor by
27012        // construction.
27013        for nome in ["hello-rio", "cart", "worker", "checkout", "a"] {
27014            let chart = lareira_chart_name(nome);
27015            assert!(
27016                is_dns_1123_label(&chart).is_ok(),
27017                "lareira_chart_name({nome:?}) = {chart:?} must be a valid DNS-1123 label"
27018            );
27019        }
27020    }
27021
27022    #[test]
27023    fn lareira_chart_name_prefix_is_a_valid_dns_1123_segment_continuation() {
27024        // The lifted prefix is one substring of the rendered chart
27025        // name; pin its grammar so a future rebrand can't land a
27026        // value that would invalidate the joint DNS-1123 label
27027        // structurally. The prefix must:
27028        //   - be lowercase ASCII alphanumeric + hyphen (the DNS-1123
27029        //     accepted set), so its bytes don't widen the joint
27030        //     accepted set;
27031        //   - end with a hyphen (so the concatenation slot doesn't
27032        //     accidentally merge with the leading character of the
27033        //     `:nome` it precedes).
27034        assert!(
27035            LAREIRA_CHART_NAME_PREFIX
27036                .bytes()
27037                .all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-'),
27038            "LAREIRA_CHART_NAME_PREFIX {LAREIRA_CHART_NAME_PREFIX:?} must use only DNS-1123-label \
27039             bytes (lowercase ASCII alphanumeric + hyphen)"
27040        );
27041        assert!(
27042            LAREIRA_CHART_NAME_PREFIX.ends_with('-'),
27043            "LAREIRA_CHART_NAME_PREFIX {LAREIRA_CHART_NAME_PREFIX:?} must end with `-` so \
27044             concatenation with the caixa's `:nome` produces a hyphenated joint label"
27045        );
27046    }
27047
27048    // ── is_lareira_chart_name_shape — joint-length budget on `:nome` ─────
27049    //
27050    // The canonical [`lareira_chart_name`] helper's own doc comment
27051    // (f7320d7) explicitly defers: "the M4 admission webhook will pin
27052    // the joint-length invariant when it lands". These tests land it
27053    // at the manifest-validate layer instead — the predicate consults
27054    // [`lareira_chart_name`] + [`is_dns_1123_label`] (no third primitive)
27055    // so a future rebrand of either axis re-derives the budget
27056    // mechanically and the test suite re-pins through the same lifts.
27057
27058    #[test]
27059    fn lareira_chart_name_nome_max_len_pins_arithmetic() {
27060        // Pin the arithmetic so a future shift in either input axis
27061        // surfaces here. The const is mechanically derived from
27062        // [`DNS_1123_LABEL_MAX_LEN`] (63 — the K8s apiserver cap every
27063        // chart-name-derived `metadata.name` inherits) minus
27064        // [`LAREIRA_CHART_NAME_PREFIX`].len() (8 — the canonical
27065        // chart-name prefix the lift f7320d7 made structural). The
27066        // landing value: 55 bytes the caixa's `:nome` may itself
27067        // occupy under the joint chart-name cap.
27068        assert_eq!(LAREIRA_CHART_NAME_NOME_MAX_LEN, 55);
27069        assert_eq!(
27070            LAREIRA_CHART_NAME_NOME_MAX_LEN,
27071            DNS_1123_LABEL_MAX_LEN - LAREIRA_CHART_NAME_PREFIX.len()
27072        );
27073    }
27074
27075    #[test]
27076    fn is_lareira_chart_name_shape_accepts_canonical_fixtures() {
27077        // Positive control: every in-tree fixture `:nome` (caixa-helm,
27078        // caixa-flux, caixa-mesh, caixa-tatara tests, the
27079        // checkout-aplicacao example) sits far below the cap. The
27080        // predicate must not regress this baseline shape.
27081        for nome in [
27082            "hello-rio",
27083            "cart",
27084            "worker",
27085            "checkout",
27086            "a",
27087            "akeyless-attest",
27088        ] {
27089            is_lareira_chart_name_shape(nome).unwrap_or_else(|e| {
27090                panic!("canonical :nome {nome:?} must pass chart-name budget, got {e:?}")
27091            });
27092        }
27093    }
27094
27095    #[test]
27096    fn is_lareira_chart_name_shape_accepts_nome_at_budget() {
27097        // Boundary-accepting case at the 55-byte cap — the joint
27098        // chart name is exactly 63 bytes, the DNS-1123 label cap.
27099        let at_cap = "a".repeat(LAREIRA_CHART_NAME_NOME_MAX_LEN);
27100        assert_eq!(at_cap.len(), LAREIRA_CHART_NAME_NOME_MAX_LEN);
27101        is_lareira_chart_name_shape(&at_cap).unwrap();
27102        assert_eq!(lareira_chart_name(&at_cap).len(), DNS_1123_LABEL_MAX_LEN);
27103    }
27104
27105    #[test]
27106    fn is_lareira_chart_name_shape_rejects_nome_one_over_budget() {
27107        // Fail-before-pass-after pin: 56 bytes is the smallest `:nome`
27108        // length that overflows the joint chart-name cap. The inner
27109        // [`is_dns_1123_label`] check accepts it (56 ≤ 63), so prior
27110        // to this gate it silently passed `Caixa::validate_nome` and
27111        // surfaced as a `helm lint` / apiserver rejection on the
27112        // rendered chart name far from the source caixa.lisp.
27113        let over = "a".repeat(LAREIRA_CHART_NAME_NOME_MAX_LEN + 1);
27114        let err = is_lareira_chart_name_shape(&over).unwrap_err();
27115        assert!(
27116            err.contains("63") && err.contains("64") && err.contains("55"),
27117            "diagnostic must name the DNS-1123 cap (63), the actual chart-name length (64), \
27118             and the per-`:nome` budget (55), got {err:?}"
27119        );
27120        assert!(
27121            err.contains("lareira-"),
27122            "diagnostic must name the canonical prefix verbatim, got {err:?}"
27123        );
27124    }
27125
27126    #[test]
27127    fn is_lareira_chart_name_shape_diagnostic_carries_offending_chart_name() {
27128        // The rendered chart name appears verbatim in the diagnostic
27129        // so the author sees exactly the string the apiserver would
27130        // have rejected — no re-derivation required to grep the source.
27131        let over = "x".repeat(LAREIRA_CHART_NAME_NOME_MAX_LEN + 5);
27132        let err = is_lareira_chart_name_shape(&over).unwrap_err();
27133        let expected_chart = lareira_chart_name(&over);
27134        assert!(
27135            err.contains(&expected_chart),
27136            "diagnostic must carry the rendered chart name {expected_chart:?} verbatim, \
27137             got {err:?}"
27138        );
27139    }
27140
27141    #[test]
27142    fn is_lareira_chart_name_shape_composes_through_canonical_helper() {
27143        // Cross-axis invariant: the predicate is defined exactly as
27144        // `is_dns_1123_label(lareira_chart_name(nome))` for the length
27145        // arm — no inline `format!("lareira-{nome}")` shape duplicating
27146        // the canonical lift. Pinning this composition closes the
27147        // drift footgun where a future predicate refactor re-inlines
27148        // the prefix-and-`:nome` concatenation and diverges from the
27149        // canonical helper. Sweep across the boundary so both sides
27150        // (accept + reject) consult the same helper.
27151        for delta in 0..=2usize {
27152            let nome = "z".repeat(LAREIRA_CHART_NAME_NOME_MAX_LEN.saturating_sub(delta));
27153            let predicate_ok = is_lareira_chart_name_shape(&nome).is_ok();
27154            let canonical_ok = is_dns_1123_label(&lareira_chart_name(&nome)).is_ok();
27155            assert_eq!(
27156                predicate_ok,
27157                canonical_ok,
27158                "predicate / canonical-composition divergence for :nome of len {} \
27159                 (predicate_ok = {predicate_ok}, canonical_ok = {canonical_ok})",
27160                nome.len()
27161            );
27162        }
27163    }
27164
27165    // ── OCI chart-ref composer — `oci://<registry>/lareira-<nome>` ───────
27166    //
27167    // Peer to the `lareira_chart_name` composer above on the sibling
27168    // OCI-artifact-reference axis. Until this lift landed the
27169    // `caixa-tatara`'s `derive_chart_ref` carried an inline
27170    // `format!("oci://{registry}/{chart}")` — a 2-axis composition
27171    // (the `oci://` scheme prefix + the `lareira-<nome>` chart name)
27172    // whose byte-shape had no compile-time link to the historical doc
27173    // comments across `caixa-core`, `caixa-flux`, `caixa-helm`, and
27174    // `caixa-tatara` promising the same shape. Pin the const, the
27175    // composition equation, and the byte-shape against the prior
27176    // inline `format!` so a future composer-internal drift fires at
27177    // test time.
27178
27179    #[test]
27180    fn oci_scheme_prefix_pins_canonical_value() {
27181        // Pin the actual string value so a typo on the canonical lift
27182        // can't silently rebrand the substrate's OCI-artifact-reference
27183        // scheme. The string is part of the contract with the Helm 3
27184        // OCI storage protocol (`helm push chart.tgz oci://…`,
27185        // `helm registry login <registry>`, `helm install release
27186        // oci://…`) and the FluxCD `HelmRepository` `type: oci` source
27187        // (Flux source-controller keys off this literal on the OCI
27188        // path); changing it is a coordinated multi-repo migration,
27189        // not an incidental edit. Peer to
27190        // [`lareira_chart_name_prefix_pins_canonical_value`] on the
27191        // sibling canonical-string-value-pin axis.
27192        assert_eq!(OCI_SCHEME_PREFIX, "oci://");
27193    }
27194
27195    #[test]
27196    fn oci_chart_ref_pins_byte_shape_against_prior_inline_format() {
27197        // Byte-shape pin against the prior inline
27198        // `format!("oci://{registry}/{chart}")` at
27199        // caixa-tatara/src/lib.rs:202 (where `chart` was itself
27200        // `lareira_chart_name(caixa.nome.as_str())`). Any future
27201        // composer-internal drift on either axis (the `oci://` scheme
27202        // prefix, the `/` scheme-authority separator, the composition
27203        // with `lareira_chart_name`) surfaces here as a byte-shape
27204        // regression rather than at cluster-apply time far from the
27205        // drift site.
27206        assert_eq!(
27207            oci_chart_ref("ghcr.io/pleme-io/charts", "akeyless-attest"),
27208            "oci://ghcr.io/pleme-io/charts/lareira-akeyless-attest"
27209        );
27210        assert_eq!(
27211            oci_chart_ref("ghcr.io/pleme-io", "hello-rio"),
27212            "oci://ghcr.io/pleme-io/lareira-hello-rio"
27213        );
27214    }
27215
27216    #[test]
27217    fn oci_chart_ref_composes_through_canonical_helpers() {
27218        // Structural composition equation: the OCI chart-ref is
27219        // exactly `{OCI_SCHEME_PREFIX}{registry}/{lareira_chart_name(nome)}`
27220        // — no inline `"oci://"` scheme literal, no inline
27221        // `format!("lareira-{}", nome)` prefix duplication. Pinning
27222        // this composition closes the drift footgun where a future
27223        // composer refactor re-inlines either axis and diverges from
27224        // its canonical source of truth. Sweep across the canonical
27225        // fixture set so the composition holds for the same `:nome`
27226        // values every peer per-Servico renderer consults.
27227        for (registry, nome) in [
27228            ("ghcr.io/pleme-io/charts", "hello-rio"),
27229            ("ghcr.io/pleme-io", "cart"),
27230            ("registry.example.com", "worker"),
27231            ("localhost:5000", "checkout"),
27232        ] {
27233            let composed = oci_chart_ref(registry, nome);
27234            let expected = format!("{OCI_SCHEME_PREFIX}{registry}/{}", lareira_chart_name(nome));
27235            assert_eq!(
27236                composed, expected,
27237                "oci_chart_ref({registry:?}, {nome:?}) must equal the canonical composition \
27238                 through OCI_SCHEME_PREFIX + lareira_chart_name"
27239            );
27240        }
27241    }
27242
27243    #[test]
27244    fn oci_chart_ref_starts_with_scheme_prefix() {
27245        // Cross-axis invariant: every output of the composer begins
27246        // with the lifted scheme prefix verbatim — a future refactor
27247        // that accidentally introduced a different scheme (e.g. a
27248        // `https://` transposition, or a scheme-authority separator
27249        // drift) would surface here. Peer to
27250        // [`lareira_chart_name_starts_with_prefix`] on the sibling
27251        // per-composer prefix-anchoring axis.
27252        for (registry, nome) in [
27253            ("ghcr.io/pleme-io/charts", "hello-rio"),
27254            ("ghcr.io/pleme-io", "cart"),
27255            ("localhost:5000", "a"),
27256        ] {
27257            let composed = oci_chart_ref(registry, nome);
27258            assert!(
27259                composed.starts_with(OCI_SCHEME_PREFIX),
27260                "oci_chart_ref({registry:?}, {nome:?}) = {composed:?} must start with the lifted \
27261                 prefix {OCI_SCHEME_PREFIX:?}"
27262            );
27263        }
27264    }
27265
27266    #[test]
27267    fn oci_chart_ref_contains_lareira_chart_name_verbatim() {
27268        // Cross-axis invariant: every output of the composer contains
27269        // the canonical `lareira_chart_name(nome)` output verbatim as
27270        // its trailing segment — a future refactor that accidentally
27271        // introduced a case fold, a hyphen-collapse, or a different
27272        // prefix-application shape would surface here. Structurally
27273        // pins that the OCI chart-ref path and the peer per-Servico
27274        // renderer chart-name path (caixa-helm's `ChartDir.name`,
27275        // caixa-flux's `HelmRelease` `chart:` field) both reach for
27276        // the same canonical `lareira_chart_name` helper's output.
27277        for (registry, nome) in [
27278            ("ghcr.io/pleme-io/charts", "hello-rio"),
27279            ("ghcr.io/pleme-io", "cart"),
27280        ] {
27281            let composed = oci_chart_ref(registry, nome);
27282            let chart = lareira_chart_name(nome);
27283            assert!(
27284                composed.ends_with(&chart),
27285                "oci_chart_ref({registry:?}, {nome:?}) = {composed:?} must end with the canonical \
27286                 lareira_chart_name({nome:?}) = {chart:?}"
27287            );
27288        }
27289    }
27290
27291    // ── Flux Kustomization source-sub-tree composer ───────────────────────
27292    //
27293    // Peer to the `oci_chart_ref` / `cilium_network_policy_name` /
27294    // `gateway_api_http_route_name` composers above on the sibling
27295    // canonical-load-bearing-scalar-that-consumers-key-off axis. Until
27296    // this lift landed the two-axis composition
27297    // (`./clusters/<cluster>/services/<nome>`) sat as an inline
27298    // `format!` template at the sole `caixa-flux::cluster_bundle`
27299    // `kustomization.yaml` production emit site plus a mirror-symmetric
27300    // inline `format!` at its paired test-fixture navigation site — no
27301    // compile-time link between the two sites and no compile-time link
27302    // ahead of the second production-emit occurrence the M4
27303    // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
27304    // `Kustomization` synthesis will surface. Pin the byte-shape, the
27305    // composition equation, and the sub-tree-scope invariants against
27306    // the prior inline `format!` so a future composer-internal drift
27307    // fires at test time.
27308
27309    #[test]
27310    fn flux_kustomization_source_subtree_pins_byte_shape_against_prior_inline_format() {
27311        // Byte-shape pin against the prior inline
27312        // `format!("./clusters/{cluster}/services/{name}")` at
27313        // caixa-flux/src/lib.rs (both the `cluster_bundle`
27314        // `kustomization.yaml` `spec.path` production emit site and the
27315        // paired `cluster_bundle_kustomization_path_pins_lifted_sub_tree`
27316        // test-fixture navigation site). Any future composer-internal
27317        // drift on either axis (the `./clusters/` per-cluster prefix,
27318        // the `/services/` per-caixa infix, the trailing per-caixa
27319        // suffix, the composition order) surfaces here as a byte-shape
27320        // regression rather than at cluster-apply time far from the
27321        // drift site.
27322        assert_eq!(
27323            flux_kustomization_source_subtree("rio", "hello-rio"),
27324            "./clusters/rio/services/hello-rio"
27325        );
27326        assert_eq!(
27327            flux_kustomization_source_subtree("paris", "cart"),
27328            "./clusters/paris/services/cart"
27329        );
27330        assert_eq!(
27331            flux_kustomization_source_subtree("tokyo", "checkout"),
27332            "./clusters/tokyo/services/checkout"
27333        );
27334    }
27335
27336    #[test]
27337    fn flux_kustomization_source_subtree_starts_with_relative_clusters_prefix() {
27338        // Structural invariant: every output starts with the canonical
27339        // `./clusters/` per-cluster-prefix half of the sub-tree seed.
27340        // The leading `./` scopes the emit to the GitRepository root
27341        // (the kustomize-controller keys the per-CR reconcile loop off
27342        // the GitRepository the paired `sourceRef` names, so the sub-
27343        // tree seed must resolve relative to the GitRepository root,
27344        // not an absolute filesystem path). The `clusters/` component
27345        // scopes the emit to the paired cluster's manifest set under
27346        // the pleme-io k8s repository's canonical directory-tree
27347        // layout.
27348        for (cluster, nome) in [
27349            ("rio", "hello-rio"),
27350            ("paris", "cart"),
27351            ("tokyo", "checkout"),
27352        ] {
27353            let sub = flux_kustomization_source_subtree(cluster, nome);
27354            assert!(
27355                sub.starts_with("./clusters/"),
27356                "flux_kustomization_source_subtree({cluster:?}, {nome:?}) = {sub:?} must start \
27357                 with the canonical `./clusters/` GitRepository-root-relative per-cluster prefix"
27358            );
27359        }
27360    }
27361
27362    #[test]
27363    fn flux_kustomization_source_subtree_contains_paired_cluster_and_nome() {
27364        // Cross-axis invariant: every output contains the paired
27365        // `<cluster>` and `<nome>` scalars verbatim, at their canonical
27366        // per-cluster / per-caixa sub-tree positions. A future
27367        // composer-internal drift that accidentally case-folded, hyphen-
27368        // collapsed, or transposed either axis (`./clusters/rio/services/hello-rio`
27369        // → `./clusters/hello-rio/services/rio` under a swapped
27370        // composition, `./clusters/Rio/services/HelloRio` under an
27371        // accidental case fold) would surface here as a structural
27372        // regression rather than at cluster-apply time far from the
27373        // drift site.
27374        for (cluster, nome) in [
27375            ("rio", "hello-rio"),
27376            ("paris", "cart"),
27377            ("tokyo", "checkout"),
27378            ("us-east-1", "worker"),
27379        ] {
27380            let sub = flux_kustomization_source_subtree(cluster, nome);
27381            assert!(
27382                sub.contains(&format!("/clusters/{cluster}/")),
27383                "flux_kustomization_source_subtree({cluster:?}, {nome:?}) = {sub:?} must carry \
27384                 the paired `<cluster>` scalar under its canonical per-cluster sub-tree position"
27385            );
27386            assert!(
27387                sub.ends_with(&format!("/services/{nome}")),
27388                "flux_kustomization_source_subtree({cluster:?}, {nome:?}) = {sub:?} must end with \
27389                 the paired `/services/<nome>` per-caixa sub-tree suffix"
27390            );
27391        }
27392    }
27393
27394    #[test]
27395    fn flux_kustomization_source_subtree_distinct_across_clusters_and_nomes() {
27396        // Uniqueness invariant: two distinct `(cluster, nome)` inputs
27397        // resolve to two distinct `spec.path` scalars. A composer-
27398        // internal drift that accidentally coalesced either axis onto
27399        // a constant (dropping `<cluster>` or `<nome>` from the emit)
27400        // would silently collapse two per-cluster / per-caixa
27401        // `Kustomization` CRs onto the same reconcile-target sub-tree,
27402        // routing two distinct manifest sets through the same apply
27403        // loop with no diagnostic naming the coalesce root cause.
27404        let a = flux_kustomization_source_subtree("rio", "hello-rio");
27405        let b = flux_kustomization_source_subtree("paris", "hello-rio");
27406        let c = flux_kustomization_source_subtree("rio", "cart");
27407        assert_ne!(
27408            a, b,
27409            "distinct clusters (`rio` vs `paris`) hosting the same per-caixa Servico \
27410             must resolve to distinct `spec.path` scalars — coalesce would silently route \
27411             two per-cluster reconcile loops through the same manifest sub-tree"
27412        );
27413        assert_ne!(
27414            a, c,
27415            "distinct per-caixa Servicos (`hello-rio` vs `cart`) co-resident under the \
27416             same cluster must resolve to distinct `spec.path` scalars — coalesce would \
27417             silently route two per-caixa reconcile loops through the same manifest sub-tree"
27418        );
27419    }
27420
27421    #[test]
27422    fn pleme_program_selector_carries_only_program() {
27423        let sel = pleme_program_selector("cart");
27424        assert_eq!(sel.len(), 1);
27425        assert_eq!(sel.get(LABEL_PROGRAM).map(String::as_str), Some("cart"));
27426        assert!(sel.get(LABEL_APLICACAO).is_none());
27427    }
27428
27429    #[test]
27430    fn pleme_program_in_aplicacao_selector_carries_both_axes() {
27431        let sel = pleme_program_in_aplicacao_selector("cart", "checkout");
27432        assert_eq!(sel.len(), 2);
27433        assert_eq!(sel.get(LABEL_PROGRAM).map(String::as_str), Some("cart"));
27434        assert_eq!(
27435            sel.get(LABEL_APLICACAO).map(String::as_str),
27436            Some("checkout")
27437        );
27438    }
27439
27440    #[test]
27441    fn pleme_program_in_aplicacao_selector_iterates_alphabetically() {
27442        // BTreeMap iteration is sorted by key — pin that the renderer
27443        // (which translates the selector into a serde_yaml::Mapping
27444        // by iteration) gets a deterministic key order. `aplicacao`
27445        // sorts before `program`, so the rendered YAML's
27446        // `matchLabels:` block appears in that order regardless of
27447        // call-site arg order. Mirrors the M2 overlay helper's
27448        // alphabetical-iteration determinism property
27449        // (THEORY.md §V.2.7 render determinism).
27450        let sel = pleme_program_in_aplicacao_selector("cart", "checkout");
27451        let keys: Vec<_> = sel.keys().copied().collect();
27452        assert_eq!(keys, vec![LABEL_APLICACAO, LABEL_PROGRAM]);
27453    }
27454
27455    #[test]
27456    fn pleme_program_in_aplicacao_selector_arg_order_independent() {
27457        // Renaming the program vs. the aplicacao must each only affect
27458        // its own axis — pin that the helper doesn't transpose its
27459        // args silently (a footgun the prior inline-string approach
27460        // had: `program: <de>` and `aplicacao: <name>` were two
27461        // adjacent insert() calls with structurally identical arms,
27462        // trivially swappable in a refactor).
27463        let sel = pleme_program_in_aplicacao_selector("cart", "checkout");
27464        assert_eq!(sel.get(LABEL_PROGRAM).map(String::as_str), Some("cart"));
27465        assert_eq!(
27466            sel.get(LABEL_APLICACAO).map(String::as_str),
27467            Some("checkout")
27468        );
27469        let swapped = pleme_program_in_aplicacao_selector("checkout", "cart");
27470        assert_eq!(
27471            swapped.get(LABEL_PROGRAM).map(String::as_str),
27472            Some("checkout")
27473        );
27474        assert_eq!(
27475            swapped.get(LABEL_APLICACAO).map(String::as_str),
27476            Some("cart")
27477        );
27478    }
27479
27480    #[test]
27481    fn yaml_string_mapping_empty_input_returns_empty_mapping() {
27482        // Empty input → empty Mapping. Pinned because the caller's
27483        // emptiness contract (e.g. caixa-mesh's CNP labels block: the
27484        // policy's metadata.labels exists iff there are pleme-prefixed
27485        // labels to carry) depends on this being faithful.
27486        let v: serde_yaml::Value = yaml_string_mapping(BTreeMap::<&'static str, String>::new());
27487        let m = v.as_mapping().expect("mapping shape");
27488        assert!(m.is_empty());
27489    }
27490
27491    #[test]
27492    fn yaml_string_mapping_round_trips_string_values() {
27493        let mut input = BTreeMap::new();
27494        input.insert("foo", "1".to_string());
27495        input.insert("bar", "2".to_string());
27496        let v = yaml_string_mapping(input);
27497        let m = v.as_mapping().expect("mapping shape");
27498        assert_eq!(m.len(), 2);
27499        assert_eq!(m.get("foo").and_then(|x| x.as_str()), Some("1"));
27500        assert_eq!(m.get("bar").and_then(|x| x.as_str()), Some("2"));
27501    }
27502
27503    #[test]
27504    fn yaml_string_mapping_iterates_alphabetically_on_btreemap() {
27505        // Pin that BTreeMap input → alphabetical iteration → alphabetical
27506        // YAML key order. THEORY.md §V.2.7 render determinism.
27507        let mut input = BTreeMap::new();
27508        input.insert("zebra", "z".to_string());
27509        input.insert("apple", "a".to_string());
27510        input.insert("mango", "m".to_string());
27511        let v = yaml_string_mapping(input);
27512        let m = v.as_mapping().expect("mapping shape");
27513        let keys: Vec<&str> = m.iter().filter_map(|(k, _)| k.as_str()).collect();
27514        assert_eq!(keys, vec!["apple", "mango", "zebra"]);
27515    }
27516
27517    #[test]
27518    fn yaml_string_mapping_accepts_pleme_selector_helpers() {
27519        // The lift's load-bearing use case: passing the typed pleme-io
27520        // selectors directly into yaml_string_mapping yields the K8s
27521        // matchLabels surface every Cilium / Gateway selector field
27522        // expects, with the alphabetical key order the pleme helpers'
27523        // own determinism contract guarantees. Pinning end-to-end
27524        // composition so a future refactor of either helper can't
27525        // silently break the integration.
27526        let v = yaml_string_mapping(pleme_program_in_aplicacao_selector("cart", "checkout"));
27527        let m = v.as_mapping().expect("mapping shape");
27528        assert_eq!(m.len(), 2);
27529        assert_eq!(m.get(LABEL_PROGRAM).and_then(|x| x.as_str()), Some("cart"));
27530        assert_eq!(
27531            m.get(LABEL_APLICACAO).and_then(|x| x.as_str()),
27532            Some("checkout")
27533        );
27534    }
27535
27536    #[test]
27537    fn kube_key_consts_have_expected_values() {
27538        // Pin the actual string values — these are part of the K8s API
27539        // surface that every emitted artifact's apiserver-side parser
27540        // (Cilium, Gateway API, wasm-operator) depends on. Changing any
27541        // of them is a coordinated multi-renderer migration, not an
27542        // incidental edit.
27543        assert_eq!(KUBE_KEY_API_VERSION, "apiVersion");
27544        assert_eq!(KUBE_KEY_KIND, "kind");
27545        assert_eq!(KUBE_KEY_METADATA, "metadata");
27546        assert_eq!(KUBE_KEY_NAME, "name");
27547        assert_eq!(KUBE_KEY_NAMESPACE, "namespace");
27548        assert_eq!(KUBE_KEY_LABELS, "labels");
27549        assert_eq!(KUBE_KEY_MATCH_LABELS, "matchLabels");
27550        assert_eq!(KUBE_KEY_PORT, "port");
27551        assert_eq!(KUBE_KEY_PROTOCOL, "protocol");
27552        assert_eq!(KUBE_KEY_RULES, "rules");
27553        assert_eq!(KUBE_KEY_SPEC, "spec");
27554    }
27555
27556    #[test]
27557    fn fleet_programs_key_programs_pins_canonical_value() {
27558        // Bridge-arm pin: [`FLEET_PROGRAMS_KEY_PROGRAMS`] resolves to
27559        // the canonical `"programs"` byte today — the exact YAML key
27560        // the `lareira-fleet-programs` library chart's `values.yaml`
27561        // reads under `.Values.programs[]` to iterate one `ComputeUnit`
27562        // CR per entry, and the exact key both writer-side upsert paths
27563        // in [`caixa_flux`] (`upsert_into_helmrelease_programs` on the
27564        // aggregator-HelmRelease shape, `upsert_into_programs_yaml` on
27565        // the bare-values.yaml shape) navigate to walk the entry
27566        // sequence. Pin the literal here (peer with the
27567        // [`M3_KEY_PLACEMENT`] / [`M2_KEY_LIMITS`] /
27568        // [`M2_KEY_BEHAVIOR`] / [`M2_KEY_UPGRADE_FROM`] canonical-
27569        // literal pins on the sibling fleet-programs / M2 overlay
27570        // schema-key surfaces) so a future fleet-programs schema-key
27571        // rebrand surfaces here as a coordinated edit-point: the
27572        // sibling caixa-flux `fleet_programs_key_programs_re_export_
27573        // points_at_caixa_core_canonical` pinning test already pins
27574        // the equality at the re-export axis; this pin closes the
27575        // second coordinate of the triangle by anchoring the lifted
27576        // constant's current byte to the canonical fleet-programs
27577        // library chart's documented shape.
27578        assert_eq!(FLEET_PROGRAMS_KEY_PROGRAMS, "programs");
27579    }
27580
27581    #[test]
27582    fn fleet_programs_key_name_pins_canonical_value() {
27583        // Bridge-arm pin: [`FLEET_PROGRAMS_KEY_NAME`] resolves to the
27584        // canonical `"name"` byte today — the exact YAML key the
27585        // `lareira-fleet-programs` library chart's `range .Values.programs`
27586        // step reads per-entry to key each rendered `ComputeUnit` CR's
27587        // `metadata.name` off, and the exact key both writer-side upsert
27588        // paths in [`caixa_flux`] (`upsert_into_helmrelease_programs` on
27589        // the aggregator-HelmRelease shape, `upsert_into_programs_yaml`
27590        // on the bare-values.yaml shape) navigate to
27591        // match-by-name-and-replace-or-append, and the exact key both
27592        // emit-side entry builders ([`caixa_flux::programs_yaml_entry`]
27593        // per-Servico, [`caixa_mesh::programs_for_aplicacao`] per-
27594        // `:membros`) write the per-entry name-axis at. Pin the literal
27595        // here (peer with the [`fleet_programs_key_programs_pins_canonical_value`]
27596        // top-level array-key canonical-literal pin on the sibling
27597        // fleet-programs schema surface, and with the
27598        // [`M3_KEY_PLACEMENT`] / [`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`]
27599        // / [`M2_KEY_UPGRADE_FROM`] canonical-literal pins on the peer
27600        // per-entry overlay-key surfaces) so a future fleet-programs
27601        // schema-key rebrand on the per-entry name-discriminator axis
27602        // surfaces here as a coordinated edit-point at the definition
27603        // site rather than a silent apply-time split between the two
27604        // emitters and the two upsert readers.
27605        assert_eq!(FLEET_PROGRAMS_KEY_NAME, "name");
27606    }
27607
27608    #[test]
27609    fn fleet_programs_key_aplicacao_pins_canonical_value() {
27610        // Bridge-arm pin: [`FLEET_PROGRAMS_KEY_APLICACAO`] resolves
27611        // to the canonical `"aplicacao"` byte today — the exact YAML
27612        // key the substrate operator's fleet-aggregator reads to
27613        // group each rendered `programs[]` entry back onto its parent
27614        // Aplicacao graph, and the exact key the
27615        // [`caixa_mesh::programs_for_aplicacao`] per-`:membros`
27616        // entry-builder writes the parent-Aplicacao-nome annotation
27617        // at. Pin the literal here (peer with the sibling
27618        // [`fleet_programs_key_name_pins_canonical_value`] and
27619        // [`fleet_programs_key_programs_pins_canonical_value`]
27620        // canonical-literal pins on the peer fleet-programs schema
27621        // key surfaces, and with the [`M3_KEY_PLACEMENT`] /
27622        // [`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] /
27623        // [`M2_KEY_UPGRADE_FROM`] pins on the per-entry overlay-key
27624        // surfaces) so a future fleet-programs schema-key rebrand
27625        // on the per-entry parent-graph-annotation axis surfaces
27626        // here as a coordinated edit-point at the definition site
27627        // rather than a silent apply-time split between the
27628        // caixa-mesh Aplicacao-side emitter and the substrate
27629        // operator's per-graph aggregator reduce step.
27630        assert_eq!(FLEET_PROGRAMS_KEY_APLICACAO, "aplicacao");
27631    }
27632
27633    #[test]
27634    fn fleet_programs_key_versao_pins_canonical_value() {
27635        // Bridge-arm pin: [`FLEET_PROGRAMS_KEY_VERSAO`] resolves to
27636        // the canonical `"versao"` byte today — the exact YAML key
27637        // the substrate operator's per-`:membros` resolver reads to
27638        // fetch each `programs[]` entry's caixa.lisp release against
27639        // the M3 Aplicacao's declared per-member semver / range
27640        // constraint, and the exact key the
27641        // [`caixa_mesh::programs_for_aplicacao`] per-`:membros`
27642        // entry-builder writes the version-constraint at. Pin the
27643        // literal here (peer with the sibling
27644        // [`fleet_programs_key_name_pins_canonical_value`],
27645        // [`fleet_programs_key_aplicacao_pins_canonical_value`], and
27646        // [`fleet_programs_key_programs_pins_canonical_value`]
27647        // canonical-literal pins on the peer fleet-programs schema
27648        // key surfaces, and with the [`M3_KEY_PLACEMENT`] /
27649        // [`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] /
27650        // [`M2_KEY_UPGRADE_FROM`] pins on the per-entry overlay-key
27651        // surfaces) so a future fleet-programs schema-key rebrand
27652        // on the per-entry version-constraint axis surfaces here as
27653        // a coordinated edit-point at the definition site rather
27654        // than a silent apply-time split between the caixa-mesh
27655        // Aplicacao-side emitter and the substrate operator's
27656        // per-`:membros` resolver step.
27657        assert_eq!(FLEET_PROGRAMS_KEY_VERSAO, "versao");
27658    }
27659
27660    // ── label_selector — typed K8s LabelSelector wrapper ─────────────────
27661
27662    #[test]
27663    fn label_selector_wraps_in_match_labels_envelope() {
27664        // The lift's contract: input labels appear under the canonical
27665        // `matchLabels` key, and the outer Value is a Mapping with
27666        // exactly that one key. Pinning the shape so a future
27667        // refactor can't silently drop the wrapper (which would emit
27668        // bare `aplicacao: …, program: …` directly under the K8s
27669        // selector field — a structurally invalid LabelSelector that
27670        // some apiserver-side parsers tolerate by matching the empty
27671        // set, a sharp footgun).
27672        let mut labels = BTreeMap::new();
27673        labels.insert(LABEL_APLICACAO, "checkout".to_string());
27674        labels.insert(LABEL_PROGRAM, "cart".to_string());
27675        let sel = label_selector(labels);
27676        let m = sel.as_mapping().expect("mapping shape");
27677        assert_eq!(m.len(), 1);
27678        let inner = m
27679            .get(KUBE_KEY_MATCH_LABELS)
27680            .and_then(|v| v.as_mapping())
27681            .expect("matchLabels inner mapping");
27682        assert_eq!(inner.len(), 2);
27683        assert_eq!(
27684            inner.get(LABEL_APLICACAO).and_then(|x| x.as_str()),
27685            Some("checkout")
27686        );
27687        assert_eq!(
27688            inner.get(LABEL_PROGRAM).and_then(|x| x.as_str()),
27689            Some("cart")
27690        );
27691    }
27692
27693    #[test]
27694    fn label_selector_empty_input_yields_empty_match_labels() {
27695        // Empty input → `{matchLabels: {}}`. The outer wrapper is
27696        // present (the K8s LabelSelector schema requires it as a
27697        // structural anchor, and apiserver-side parsers that see a
27698        // bare `{}` selector match-everything; pinning the wrapper
27699        // means an empty pleme-io selector at the call site renders
27700        // as the canonical "no labels declared, match nothing
27701        // specific" shape rather than an outright missing key).
27702        let v: serde_yaml::Value = label_selector(BTreeMap::<&'static str, String>::new());
27703        let m = v.as_mapping().expect("mapping shape");
27704        assert_eq!(m.len(), 1);
27705        let inner = m
27706            .get(KUBE_KEY_MATCH_LABELS)
27707            .and_then(|v| v.as_mapping())
27708            .expect("matchLabels inner mapping");
27709        assert!(inner.is_empty());
27710    }
27711
27712    #[test]
27713    fn label_selector_accepts_pleme_selector_helpers() {
27714        // The lift's load-bearing use case: passing the typed pleme-io
27715        // selectors directly into `label_selector` yields the K8s
27716        // LabelSelector shape every Cilium / Gateway / future
27717        // app-operator selector field expects. Pinning end-to-end
27718        // composition so a future refactor of either helper can't
27719        // silently break the integration.
27720        let v = label_selector(pleme_program_in_aplicacao_selector("cart", "checkout"));
27721        let inner = v
27722            .as_mapping()
27723            .and_then(|m| m.get(KUBE_KEY_MATCH_LABELS))
27724            .and_then(|v| v.as_mapping())
27725            .expect("matchLabels inner mapping");
27726        assert_eq!(inner.len(), 2);
27727        assert_eq!(
27728            inner.get(LABEL_PROGRAM).and_then(|x| x.as_str()),
27729            Some("cart")
27730        );
27731        assert_eq!(
27732            inner.get(LABEL_APLICACAO).and_then(|x| x.as_str()),
27733            Some("checkout")
27734        );
27735
27736        // Single-axis variant — only LABEL_PROGRAM under matchLabels.
27737        let v = label_selector(pleme_program_selector("cart"));
27738        let inner = v
27739            .as_mapping()
27740            .and_then(|m| m.get(KUBE_KEY_MATCH_LABELS))
27741            .and_then(|v| v.as_mapping())
27742            .unwrap();
27743        assert_eq!(inner.len(), 1);
27744        assert_eq!(
27745            inner.get(LABEL_PROGRAM).and_then(|x| x.as_str()),
27746            Some("cart")
27747        );
27748    }
27749
27750    #[test]
27751    fn label_selector_inner_iterates_alphabetically_on_btreemap() {
27752        // BTreeMap input → alphabetical iteration → alphabetical YAML
27753        // key order under `matchLabels`. THEORY.md §V.2.7 render
27754        // determinism: the rendered YAML's matchLabels: block appears
27755        // in a deterministic order independent of source-code
27756        // declaration order.
27757        let mut input = BTreeMap::new();
27758        input.insert("zebra", "z".to_string());
27759        input.insert("apple", "a".to_string());
27760        input.insert("mango", "m".to_string());
27761        let v = label_selector(input);
27762        let inner = v
27763            .as_mapping()
27764            .and_then(|m| m.get(KUBE_KEY_MATCH_LABELS))
27765            .and_then(|v| v.as_mapping())
27766            .unwrap();
27767        let keys: Vec<&str> = inner.iter().filter_map(|(k, _)| k.as_str()).collect();
27768        assert_eq!(keys, vec!["apple", "mango", "zebra"]);
27769    }
27770
27771    #[test]
27772    fn label_selector_does_not_introduce_match_expressions_axis() {
27773        // V0 emits matchLabels only — pinning that the helper doesn't
27774        // pre-insert an empty `matchExpressions: []` block (which some
27775        // apiserver-side parsers tolerate but renders noisily and
27776        // shifts the per-rule diff). A future set-based selector
27777        // extension is a deliberate API change to this helper, not an
27778        // incidental shape leak.
27779        let v = label_selector(pleme_program_selector("cart"));
27780        let m = v.as_mapping().unwrap();
27781        assert!(
27782            m.get("matchExpressions").is_none(),
27783            "label_selector must not pre-insert a matchExpressions key (V0 is matchLabels-only)"
27784        );
27785    }
27786
27787    #[test]
27788    fn kube_resource_skeleton_carries_three_top_level_keys_no_spec() {
27789        // The skeleton emits exactly apiVersion + kind + metadata; the
27790        // caller adds spec (and any other top-level keys) themselves.
27791        // Pin that contract so a future caller doesn't accidentally
27792        // double-insert apiVersion / kind / metadata after the
27793        // skeleton call. Namespace fixture arg reads through the
27794        // canonical `DEFAULT_NAMESPACE` const so a future rebrand of
27795        // the substrate's default namespace reaches every fixture by
27796        // construction rather than through a per-fixture stray
27797        // "tatara-system" byte-sequence.
27798        let skel = kube_resource_skeleton(
27799            "cilium.io/v2",
27800            "CiliumNetworkPolicy",
27801            "p-1",
27802            DEFAULT_NAMESPACE,
27803            BTreeMap::new(),
27804        );
27805        assert_eq!(skel.len(), 3);
27806        assert_eq!(
27807            skel.get(KUBE_KEY_API_VERSION).and_then(|v| v.as_str()),
27808            Some("cilium.io/v2")
27809        );
27810        assert_eq!(
27811            skel.get(KUBE_KEY_KIND).and_then(|v| v.as_str()),
27812            Some("CiliumNetworkPolicy")
27813        );
27814        assert!(skel.get(KUBE_KEY_METADATA).is_some());
27815    }
27816
27817    #[test]
27818    fn kube_resource_skeleton_metadata_carries_name_and_namespace() {
27819        let skel = kube_resource_skeleton(
27820            "gateway.networking.k8s.io/v1",
27821            "Gateway",
27822            "checkout",
27823            DEFAULT_NAMESPACE,
27824            BTreeMap::new(),
27825        );
27826        let metadata = skel
27827            .get(KUBE_KEY_METADATA)
27828            .and_then(|v| v.as_mapping())
27829            .expect("metadata mapping");
27830        assert_eq!(
27831            metadata.get(KUBE_KEY_NAME).and_then(|v| v.as_str()),
27832            Some("checkout")
27833        );
27834        // Read-back probe reads through `DEFAULT_NAMESPACE` so a
27835        // future substrate-namespace rebrand routes through the
27836        // canonical const on both the emit-side fixture arg and the
27837        // probe-side readback in one edit — a drift on either side
27838        // would otherwise silently mask the round-trip pin.
27839        assert_eq!(
27840            metadata.get(KUBE_KEY_NAMESPACE).and_then(|v| v.as_str()),
27841            Some(DEFAULT_NAMESPACE)
27842        );
27843    }
27844
27845    #[test]
27846    fn kube_resource_skeleton_omits_labels_when_empty() {
27847        // Empty labels → metadata.labels key absent (NOT present-as-empty).
27848        // K8s API server treats a missing labels key as "no labels
27849        // declared"; an empty-mapping `labels: {}` serializes
27850        // differently in some YAML libraries and is a sharp tool for
27851        // label-based selectors that match the empty set silently.
27852        let skel = kube_resource_skeleton(
27853            "gateway.networking.k8s.io/v1",
27854            "HTTPRoute",
27855            "r-1",
27856            DEFAULT_NAMESPACE,
27857            BTreeMap::new(),
27858        );
27859        let metadata = skel
27860            .get(KUBE_KEY_METADATA)
27861            .and_then(|v| v.as_mapping())
27862            .unwrap();
27863        assert!(
27864            metadata.get(KUBE_KEY_LABELS).is_none(),
27865            "metadata.labels must be absent when no labels passed"
27866        );
27867        // metadata then has exactly 2 keys: name, namespace.
27868        assert_eq!(metadata.len(), 2);
27869    }
27870
27871    #[test]
27872    fn kube_resource_skeleton_includes_labels_when_present() {
27873        let mut labels = BTreeMap::new();
27874        labels.insert(LABEL_APLICACAO, "checkout".to_string());
27875        labels.insert(LABEL_CONTRATO, "cart-to-catalog".to_string());
27876        let skel = kube_resource_skeleton(
27877            "cilium.io/v2",
27878            "CiliumNetworkPolicy",
27879            "p-1",
27880            DEFAULT_NAMESPACE,
27881            labels,
27882        );
27883        let metadata = skel
27884            .get(KUBE_KEY_METADATA)
27885            .and_then(|v| v.as_mapping())
27886            .unwrap();
27887        let labels_block = metadata
27888            .get(KUBE_KEY_LABELS)
27889            .and_then(|v| v.as_mapping())
27890            .expect("metadata.labels mapping present");
27891        assert_eq!(
27892            labels_block.get(LABEL_APLICACAO).and_then(|v| v.as_str()),
27893            Some("checkout")
27894        );
27895        assert_eq!(
27896            labels_block.get(LABEL_CONTRATO).and_then(|v| v.as_str()),
27897            Some("cart-to-catalog")
27898        );
27899    }
27900
27901    #[test]
27902    fn kube_resource_skeleton_metadata_iterates_alphabetically() {
27903        // Pin that the inner BTreeMap projection makes the rendered
27904        // YAML's metadata: block alphabetical (labels, name, namespace),
27905        // regardless of insert order. THEORY.md §V.2.7 render determinism.
27906        let mut labels = BTreeMap::new();
27907        labels.insert(LABEL_APLICACAO, "checkout".to_string());
27908        let skel = kube_resource_skeleton(
27909            "cilium.io/v2",
27910            "CiliumNetworkPolicy",
27911            "p-1",
27912            DEFAULT_NAMESPACE,
27913            labels,
27914        );
27915        let metadata = skel
27916            .get(KUBE_KEY_METADATA)
27917            .and_then(|v| v.as_mapping())
27918            .unwrap();
27919        let keys: Vec<&str> = metadata.iter().filter_map(|(k, _)| k.as_str()).collect();
27920        assert_eq!(
27921            keys,
27922            vec![KUBE_KEY_LABELS, KUBE_KEY_NAME, KUBE_KEY_NAMESPACE]
27923        );
27924    }
27925
27926    #[test]
27927    fn kube_resource_skeleton_top_level_iterates_in_insert_order() {
27928        // The top-level Mapping is a plain serde_yaml::Mapping (insert-
27929        // ordered), and the skeleton inserts apiVersion → kind →
27930        // metadata in that order. Pin so a future refactor doesn't
27931        // silently shift the rendered YAML's top-level key order
27932        // (which K8s tooling tolerates but humans + diff readability
27933        // care about — apiVersion-first is the K8s convention).
27934        let skel = kube_resource_skeleton(
27935            "cilium.io/v2",
27936            "CiliumNetworkPolicy",
27937            "p-1",
27938            DEFAULT_NAMESPACE,
27939            BTreeMap::new(),
27940        );
27941        let keys: Vec<&str> = skel.iter().filter_map(|(k, _)| k.as_str()).collect();
27942        assert_eq!(
27943            keys,
27944            vec![KUBE_KEY_API_VERSION, KUBE_KEY_KIND, KUBE_KEY_METADATA]
27945        );
27946    }
27947
27948    #[test]
27949    fn kube_resource_skeleton_does_not_introduce_spec_key() {
27950        // Sanity: the skeleton is metadata-only — `spec` is the caller's
27951        // responsibility. Pinning so a future "be helpful" refactor
27952        // doesn't auto-insert an empty `spec: {}` (which would silently
27953        // shadow caller-side spec construction).
27954        let skel = kube_resource_skeleton(
27955            "cilium.io/v2",
27956            "CiliumNetworkPolicy",
27957            "p-1",
27958            DEFAULT_NAMESPACE,
27959            BTreeMap::new(),
27960        );
27961        assert!(
27962            skel.get("spec").is_none(),
27963            "skeleton must not pre-insert a spec key"
27964        );
27965    }
27966
27967    // ── require_kind / KindMismatch — typed kind-check predicate ─────
27968
27969    #[test]
27970    fn require_kind_accepts_matching_kind() {
27971        // A Servico-kind caixa passes a `require_kind(_, Servico)`
27972        // check — the happy path every renderer sees on a correctly-
27973        // authored caixa.lisp, surfaced as `Ok(())` so the renderer's
27974        // call site reads as a one-liner gate rather than a typed
27975        // pattern match.
27976        let c = bare_servico();
27977        require_kind(&c, CaixaKind::Servico).unwrap();
27978    }
27979
27980    #[test]
27981    fn require_kind_rejects_with_typed_mismatch() {
27982        // A Biblioteca-kind caixa fails a `require_kind(_, Servico)`
27983        // check with a typed [`KindMismatch`] view that names the
27984        // offending caixa's `:nome` plus both the expected and actual
27985        // kinds. Pinning the typed shape so a future Display-format
27986        // tweak can't silently drop any of the three load-bearing
27987        // fields (which would regress the "feira verb whose error
27988        // path doesn't name the offending caixa" punch-list item the
27989        // protocol calls out).
27990        let mut c = bare_servico();
27991        c.kind = CaixaKind::Biblioteca;
27992        c.servicos = vec![];
27993        let err = require_kind(&c, CaixaKind::Servico).unwrap_err();
27994        assert_eq!(err.nome, "hello-rio");
27995        assert_eq!(err.expected, CaixaKind::Servico);
27996        assert_eq!(err.actual, CaixaKind::Biblioteca);
27997    }
27998
27999    #[test]
28000    fn require_kind_routes_offending_nome_via_caixa_nome_accessor() {
28001        // Pin: the [`KindMismatch::nome`] `String` the constructor
28002        // writes must be a byte-identical copy of what the lifted
28003        // [`crate::Caixa::nome`] accessor returns for the same
28004        // [`Caixa`] input — the same discipline the sibling
28005        // [`crate::LayoutInvariants::verify`] wrap-envelope emitters
28006        // pin at 9842a4b's `expected_nome_via_accessor` line (the
28007        // routing pin the 31-site converge introduced on the substrate's
28008        // own layout-invariant verifier's per-axis diagnostic emitters).
28009        //
28010        // Guardrails a future regression that re-inlines the raw
28011        // `caixa.nome.clone()` `String::clone()` of the underlying
28012        // field at the constructor site — the accessor's borrow
28013        // return + typed `.to_string()` `String` promotion is the
28014        // one canonical shape the substrate's own [`KindMismatch`]
28015        // typed-view constructor carries onto every downstream
28016        // renderer's `Error::From<KindMismatch>` `#[from]` arm, so
28017        // any drift (a byte-non-identical shape, e.g. a future
28018        // `CaixaNome` newtype the [`crate::Caixa::nome`] accessor
28019        // upgrades to project the display byte-string of, that
28020        // `.nome.clone()` would silently ignore) surfaces here
28021        // before the drift lands on a per-renderer `#[from]` arm.
28022        let mut c = bare_servico();
28023        c.kind = CaixaKind::Biblioteca;
28024        c.servicos = vec![];
28025        c.nome = "kind-mismatch-pin".into();
28026        let expected_nome_via_accessor = c.nome().to_string();
28027        assert_eq!(
28028            expected_nome_via_accessor, "kind-mismatch-pin",
28029            "the mutated fixture's `:nome` must be observable through \
28030             the accessor before the kind-mismatch gate fires",
28031        );
28032        let err = require_kind(&c, CaixaKind::Servico).unwrap_err();
28033        assert_eq!(
28034            err.nome, expected_nome_via_accessor,
28035            "the KindMismatch's `nome` field must equal \
28036             `caixa.nome().to_string()` — the typed-view constructor \
28037             must route through the lifted [`Caixa::nome`] accessor's \
28038             `.to_string()` extension, not the raw `caixa.nome.clone()` \
28039             `String::clone()` of the underlying field",
28040        );
28041    }
28042
28043    #[test]
28044    fn kind_mismatch_display_names_offending_caixa_nome() {
28045        // The Display impl is the load-bearing surface every renderer's
28046        // `#[error("{0}")] NotAXKind(#[from] KindMismatch)` arm prints
28047        // through. Pinning the exact rendered form so a future format
28048        // change is a one-line edit + a one-line test update, not a
28049        // silent regression of the diagnostic clarity.
28050        let err = KindMismatch {
28051            nome: "checkout".into(),
28052            expected: CaixaKind::Aplicacao,
28053            actual: CaixaKind::Servico,
28054        };
28055        let msg = format!("{err}");
28056        assert!(
28057            msg.contains("checkout"),
28058            "Display must name the offending caixa nome (got: {msg:?})"
28059        );
28060        assert!(
28061            msg.contains("Aplicacao"),
28062            "Display must name the expected kind (got: {msg:?})"
28063        );
28064        assert!(
28065            msg.contains("Servico"),
28066            "Display must name the actual kind (got: {msg:?})"
28067        );
28068    }
28069
28070    #[test]
28071    fn require_kind_distinguishes_every_pair_of_kinds() {
28072        // Sanity: the predicate is kind-axis-agnostic — it works for
28073        // every kind / expected pair, not just Servico/Biblioteca.
28074        // Pinning that the caller can use `require_kind` for any of
28075        // the five typed kinds (Biblioteca, Binario, Servico,
28076        // Supervisor, Aplicacao) without a special-cased helper per
28077        // kind. Same idiom every per-target renderer key off.
28078        let mut c = bare_servico();
28079        c.kind = CaixaKind::Aplicacao;
28080        c.servicos = vec![];
28081        let err = require_kind(&c, CaixaKind::Supervisor).unwrap_err();
28082        assert_eq!(err.expected, CaixaKind::Supervisor);
28083        assert_eq!(err.actual, CaixaKind::Aplicacao);
28084        require_kind(&c, CaixaKind::Aplicacao).unwrap();
28085    }
28086
28087    // ── require_ci / MissingCiSlot — Acao `:ci`-slot-presence gate ────
28088
28089    fn bare_acao_without_ci() -> Caixa {
28090        let mut c = bare_servico();
28091        c.kind = CaixaKind::Acao;
28092        c.servicos = vec![];
28093        c.ci = None;
28094        c
28095    }
28096
28097    fn sample_ci_run() -> canteiro_types::CiRun {
28098        canteiro_types::CiRun {
28099            workspace: "pleme-io".into(),
28100            repo: "caixa".into(),
28101            nodes: vec![],
28102        }
28103    }
28104
28105    #[test]
28106    fn require_ci_accepts_present_slot_and_returns_borrowed_ci_run() {
28107        // The happy path: an Acao-kind caixa that declares its `:ci`
28108        // slot passes `require_ci`, and the borrowed
28109        // [`canteiro_types::CiRun`] projected through the successful
28110        // return is the same author-declared value the caller was about
28111        // to bind — folding the check and the bind onto one call site,
28112        // matching how every present + roadmapped per-`Acao` consumer
28113        // uses the slot.
28114        let mut c = bare_acao_without_ci();
28115        c.ci = Some(sample_ci_run());
28116        let ci = require_ci(&c).expect("Acao with declared :ci passes");
28117        assert_eq!(ci.workspace, "pleme-io");
28118        assert_eq!(ci.repo, "caixa");
28119    }
28120
28121    #[test]
28122    fn require_ci_rejects_absent_slot_with_typed_view() {
28123        // The fail-before-pass-after pin: pre-lift `caixa-actions`'
28124        // inline `.ok_or_else(|| Error::MissingCi { nome:
28125        // caixa.nome().to_string() })` gate constructed an
28126        // `Error::MissingCi { nome: String }` at exactly one crate's
28127        // call site with no compile-time link to any typed named-caixa
28128        // view the sibling per-renderer entry-gate axes carry. A future
28129        // per-`Acao` consumer (the deferred `sui-supercacheci::canteiro
28130        // ::emit_gha` workflow renderer named in the `caixa-actions`
28131        // crate docs, the future per-`Acao` CR materializer) would
28132        // re-inline the same `.ok_or_else(...)` construction on its own
28133        // call site and open a second untracked `nome: String`-carry
28134        // path — exactly the "feira verb whose error path doesn't name
28135        // the offending caixa" punch-list item the compounding-mandate
28136        // protocol calls out. Lifting the gate onto the typed
28137        // [`MissingCiSlot`] view + [`require_ci`] predicate closes the
28138        // drift potential structurally: every future per-`Acao`
28139        // consumer reaches for the same one-liner + `#[from]` and gets
28140        // the diagnostic-naming-the-offending-caixa contract for free.
28141        let c = bare_acao_without_ci();
28142        let err = require_ci(&c).unwrap_err();
28143        assert_eq!(err.nome, "hello-rio");
28144    }
28145
28146    #[test]
28147    fn require_ci_routes_offending_nome_via_caixa_nome_accessor() {
28148        // Pin: the [`MissingCiSlot::nome`] `String` the constructor
28149        // writes must be a byte-identical copy of what the lifted
28150        // [`crate::Caixa::nome`] accessor returns for the same
28151        // [`Caixa`] input — the same routing pin discipline the peer
28152        // [`require_kind`] / [`require_single_servico`] typed views
28153        // already carry, so a future regression that re-inlines a raw
28154        // `caixa.nome.clone()` `String::clone()` of the underlying
28155        // field at the constructor site (which would silently ignore
28156        // any future `CaixaNome` newtype the [`crate::Caixa::nome`]
28157        // accessor upgrades to project the display byte-string of)
28158        // trips here before the drift lands on a per-consumer `#[from]`
28159        // arm.
28160        let mut c = bare_acao_without_ci();
28161        c.nome = "missing-ci-pin".into();
28162        let expected_nome_via_accessor = c.nome().to_string();
28163        assert_eq!(
28164            expected_nome_via_accessor, "missing-ci-pin",
28165            "the mutated fixture's `:nome` must be observable through \
28166             the accessor before the `:ci` gate fires",
28167        );
28168        let err = require_ci(&c).unwrap_err();
28169        assert_eq!(
28170            err.nome, expected_nome_via_accessor,
28171            "the MissingCiSlot's `nome` field must equal \
28172             `caixa.nome().to_string()` — the typed-view constructor \
28173             must route through the lifted [`Caixa::nome`] accessor's \
28174             `.to_string()` extension, not the raw `caixa.nome.clone()` \
28175             `String::clone()` of the underlying field",
28176        );
28177    }
28178
28179    #[test]
28180    fn missing_ci_slot_display_names_offending_caixa_nome() {
28181        // The Display impl is the load-bearing surface every per-
28182        // `Acao` consumer's `#[error("{0}")] MissingCi(#[from]
28183        // MissingCiSlot)` arm prints through. Pinning the exact rendered
28184        // form so a future format change is a one-line edit + a one-line
28185        // test update, not a silent regression of the diagnostic
28186        // clarity. Same shape every peer per-axis lift carries.
28187        let err = MissingCiSlot {
28188            nome: "hello-acao".into(),
28189        };
28190        let msg = format!("{err}");
28191        assert!(
28192            msg.contains("hello-acao"),
28193            "Display must name the offending caixa nome (got: {msg:?})"
28194        );
28195        assert!(
28196            msg.contains(":ci"),
28197            "Display must name the missing `:ci` slot (got: {msg:?})"
28198        );
28199    }
28200
28201    // ── CiDecomposeFailure — per-`Acao` decompose-failure diagnostic axis ─
28202
28203    #[test]
28204    fn ci_decompose_failure_carries_offending_nome_and_source_verbatim() {
28205        // Fail-before-pass-after pin on the [`CiDecomposeFailure`] typed
28206        // view: the constructor writes the offending caixa's `:nome`
28207        // (routed through the lifted [`crate::Caixa::nome`] accessor's
28208        // `.to_string()` extension by every consumer) alongside the
28209        // borrowed [`canteiro_types::DecomposeError`] source verbatim,
28210        // so a per-`Acao` consumer that fans on the specific
28211        // decompose-failure arm reaches for `err.source` directly
28212        // rather than re-parsing the Display bytes. Peer of the sibling
28213        // [`MissingCiSlot`] typed view's `nome`-carrying pin — extends
28214        // the same "one typed view per axis, carrying the offending
28215        // caixa's `:nome` + axis-specific detail" discipline onto the
28216        // second per-`Acao` diagnostic axis after the presence-gate
28217        // axis.
28218        let err = CiDecomposeFailure {
28219            nome: "hello-acao".into(),
28220            source: canteiro_types::DecomposeError::Cycle,
28221        };
28222        assert_eq!(err.nome, "hello-acao");
28223        assert_eq!(err.source, canteiro_types::DecomposeError::Cycle);
28224    }
28225
28226    #[test]
28227    fn ci_decompose_failure_display_names_offending_caixa_nome_and_source() {
28228        // The Display impl is the load-bearing surface every per-`Acao`
28229        // consumer's `#[error("{0}")] Decompose(#[from]
28230        // CiDecomposeFailure)` arm prints through. Pinning the exact
28231        // rendered form so a future format change is a one-line edit +
28232        // a one-line test update, not a silent regression of the
28233        // diagnostic clarity — same shape every peer per-axis lift
28234        // carries.
28235        let err = CiDecomposeFailure {
28236            nome: "hello-acao".into(),
28237            source: canteiro_types::DecomposeError::Cycle,
28238        };
28239        let msg = format!("{err}");
28240        assert!(
28241            msg.contains("hello-acao"),
28242            "Display must name the offending caixa nome (got: {msg:?})"
28243        );
28244        assert!(
28245            msg.contains(":ci"),
28246            "Display must name the `:ci` slot the decompose failed on \
28247             (got: {msg:?})"
28248        );
28249        assert!(
28250            msg.contains("decompose"),
28251            "Display must name the decompose axis (got: {msg:?})"
28252        );
28253    }
28254
28255    #[test]
28256    fn ci_decompose_failure_exposes_source_via_error_trait() {
28257        // Pin: the [`CiDecomposeFailure`] type routes its
28258        // [`canteiro_types::DecomposeError`] carrier through the
28259        // `#[source]` [`thiserror::Error`] derive so downstream
28260        // `std::error::Error::source()`-consuming diagnostic frameworks
28261        // (`anyhow`'s chain formatter, `tracing`'s `error!` event
28262        // capture, the future `feira lint` sub-diagnostic emitter) see
28263        // the underlying `DecomposeError` arm through the standard
28264        // trait rather than only through the flattened Display bytes.
28265        // Peer of the sibling per-slot `#[source]` wiring the caixa-*
28266        // renderers already carry on their own typed-view error
28267        // wrappers.
28268        let err = CiDecomposeFailure {
28269            nome: "hello-acao".into(),
28270            source: canteiro_types::DecomposeError::Cycle,
28271        };
28272        let src = std::error::Error::source(&err)
28273            .expect("CiDecomposeFailure must expose its DecomposeError via Error::source()");
28274        // The `Error::source()` trait method returns a `&dyn Error`
28275        // borrow of the underlying `DecomposeError`, so its Display
28276        // bytes must equal the source arm's own Display bytes — a
28277        // future accidental collapse of the `#[source]` wiring (which
28278        // would erase the source chain and force downstream
28279        // `anyhow::Chain` consumers back onto Display re-parsing) trips
28280        // here at caixa-core build time.
28281        let src_msg = format!("{src}");
28282        let expected_msg = format!("{}", canteiro_types::DecomposeError::Cycle);
28283        assert_eq!(src_msg, expected_msg);
28284    }
28285
28286    // ── decompose_ci — per-`Acao` decompose-axis predicate ────────────
28287
28288    fn cyclic_ci_run() -> canteiro_types::CiRun {
28289        // A minimal two-node cycle: `a` depends on `b`, `b` depends on
28290        // `a`. Every failure mode `canteiro_types::decompose` refuses
28291        // (duplicate node name, missing dependency, cycle) would work as
28292        // a fixture; the cycle arm is the same one the `caixa-actions`
28293        // per-`Acao` renderer's own `validate_rejects_a_cyclic_ci_run`
28294        // test already reads for, so both the substrate primitive's own
28295        // pin and the consumer's byte-parity pin share one canonical
28296        // fixture shape.
28297        canteiro_types::CiRun {
28298            workspace: "pleme-io".into(),
28299            repo: "caixa".into(),
28300            nodes: vec![
28301                canteiro_types::CiNode::new(
28302                    "a",
28303                    canteiro_types::EnvClass::None,
28304                    canteiro_types::ActionRef {
28305                        name: "a".into(),
28306                        command: "true".into(),
28307                        args: vec![],
28308                    },
28309                    vec!["b".into()],
28310                ),
28311                canteiro_types::CiNode::new(
28312                    "b",
28313                    canteiro_types::EnvClass::None,
28314                    canteiro_types::ActionRef {
28315                        name: "b".into(),
28316                        command: "true".into(),
28317                        args: vec![],
28318                    },
28319                    vec!["a".into()],
28320                ),
28321            ],
28322        }
28323    }
28324
28325    fn linear_ci_run() -> canteiro_types::CiRun {
28326        // A minimal two-node acyclic run: `test` depends on `build`.
28327        // Same shape as the `caixa-actions` `validate_decomposes_a_two_
28328        // node_build_then_test_run` happy-path test — one shared
28329        // canonical fixture for every downstream substrate consumer.
28330        canteiro_types::CiRun {
28331            workspace: "pleme-io".into(),
28332            repo: "caixa".into(),
28333            nodes: vec![
28334                canteiro_types::CiNode::new(
28335                    "build",
28336                    canteiro_types::EnvClass::None,
28337                    canteiro_types::ActionRef {
28338                        name: "build".into(),
28339                        command: "true".into(),
28340                        args: vec![],
28341                    },
28342                    vec![],
28343                ),
28344                canteiro_types::CiNode::new(
28345                    "test",
28346                    canteiro_types::EnvClass::None,
28347                    canteiro_types::ActionRef {
28348                        name: "test".into(),
28349                        command: "true".into(),
28350                        args: vec![],
28351                    },
28352                    vec!["build".into()],
28353                ),
28354            ],
28355        }
28356    }
28357
28358    #[test]
28359    fn decompose_ci_accepts_valid_ci_run_and_returns_canteiro_dag() {
28360        // The happy path: a valid two-node acyclic run decomposes
28361        // cleanly through `decompose_ci`, returning the owned
28362        // `canteiro_types::CanteiroDag` the sibling `canteiro_types::
28363        // decompose` returns — the substrate primitive is a
28364        // pass-through on success, only wrapping the error arm in a
28365        // typed named-caixa view. Matches the peer `require_ci`
28366        // presence-axis happy path (accept-with-borrowed-CiRun) —
28367        // extends the "one primitive per axis, pass-through on success"
28368        // discipline onto the decompose axis.
28369        let c = bare_acao_without_ci();
28370        let ci = linear_ci_run();
28371        let cd = decompose_ci(&c, &ci).expect("valid acyclic CiRun decomposes cleanly");
28372        // The topo_order() call on a successful decompose is infallible
28373        // by construction (no cycles present), so a downstream consumer
28374        // reaches for the DAG's own algebra directly rather than a
28375        // second gate. Iterating the returned order (rather than
28376        // asserting on a concrete container shape) keeps the pin
28377        // agnostic to whether topo_order returns Vec<NodeId>,
28378        // SmallVec<NodeId>, or any future returned collection.
28379        let topo = cd
28380            .topo_order()
28381            .expect("acyclic CanteiroDag returns a valid topo_order");
28382        assert_eq!(
28383            topo.iter().count(),
28384            2,
28385            "topo_order on a two-node acyclic run must yield two node ids"
28386        );
28387    }
28388
28389    #[test]
28390    fn decompose_ci_rejects_cyclic_ci_run_with_typed_view() {
28391        // The fail-before-pass-after pin: pre-lift `caixa-actions`'
28392        // inline `.map_err(|source| CiDecomposeFailure { nome: nome
28393        // .clone(), source })` gate constructed a `CiDecomposeFailure`
28394        // at exactly one crate's call site with no compile-time link to
28395        // any typed named-caixa predicate the sibling per-`Acao` /
28396        // per-renderer entry-gate axes carry. A future per-`Acao`
28397        // consumer (the deferred `sui-supercacheci::canteiro::emit_gha`
28398        // workflow renderer named in the `caixa-actions` crate docs, a
28399        // future per-`Acao` CR materializer's admission webhook) would
28400        // re-inline the same `.map_err(...)` construction on its own
28401        // call site and open a second untracked
28402        // `caixa.nome().to_string()` re-projection path — exactly the
28403        // "feira verb whose error path doesn't name the offending
28404        // caixa" punch-list item the compounding-mandate protocol calls
28405        // out. Lifting the gate onto the typed `decompose_ci` predicate
28406        // closes the drift potential structurally: every future
28407        // per-`Acao` consumer reaches for the same one-liner + `#[from]`
28408        // and gets the diagnostic-naming-the-offending-caixa contract
28409        // for free.
28410        let c = bare_acao_without_ci();
28411        let ci = cyclic_ci_run();
28412        // `unwrap_err()` needs `T: Debug`, and the Ok half here carries
28413        // `canteiro_types::CanteiroDag`, which does not derive it at the
28414        // pinned sui rev — so the whole caixa-core test target failed to
28415        // COMPILE. A let-else says the same thing without borrowing a
28416        // bound from a foreign type we do not own.
28417        let Err(err) = decompose_ci(&c, &ci) else {
28418            panic!("a cyclic CiRun must fail decompose_ci");
28419        };
28420        assert_eq!(err.nome, "hello-rio");
28421        assert_eq!(err.source, canteiro_types::DecomposeError::Cycle);
28422    }
28423
28424    #[test]
28425    fn decompose_ci_routes_offending_nome_via_caixa_nome_accessor() {
28426        // Pin: the `CiDecomposeFailure::nome` `String` the constructor
28427        // writes must be a byte-identical copy of what the lifted
28428        // `crate::Caixa::nome` accessor returns for the same `Caixa`
28429        // input — the same routing pin discipline the peer
28430        // `require_kind` / `require_single_servico` / `require_ci`
28431        // typed views already carry, so a future regression that
28432        // re-inlines a raw `caixa.nome.clone()` `String::clone()` of
28433        // the underlying field at the constructor site (which would
28434        // silently ignore any future `CaixaNome` newtype the
28435        // `crate::Caixa::nome` accessor upgrades to project the display
28436        // byte-string of) trips here before the drift lands on a
28437        // per-consumer `#[from]` arm.
28438        let mut c = bare_acao_without_ci();
28439        c.nome = "decompose-ci-pin".into();
28440        let expected_nome_via_accessor = c.nome().to_string();
28441        assert_eq!(
28442            expected_nome_via_accessor, "decompose-ci-pin",
28443            "the mutated fixture's `:nome` must be observable through \
28444             the accessor before the decompose gate fires",
28445        );
28446        let ci = cyclic_ci_run();
28447        // `unwrap_err()` needs `T: Debug`, and the Ok half here carries
28448        // `canteiro_types::CanteiroDag`, which does not derive it at the
28449        // pinned sui rev — so the whole caixa-core test target failed to
28450        // COMPILE. A let-else says the same thing without borrowing a
28451        // bound from a foreign type we do not own.
28452        let Err(err) = decompose_ci(&c, &ci) else {
28453            panic!("a cyclic CiRun must fail decompose_ci");
28454        };
28455        assert_eq!(
28456            err.nome, expected_nome_via_accessor,
28457            "the CiDecomposeFailure's `nome` field must equal \
28458             `caixa.nome().to_string()` — the `decompose_ci` predicate \
28459             must route through the lifted `Caixa::nome` accessor's \
28460             `.to_string()` extension, not a raw `caixa.nome.clone()` \
28461             `String::clone()` of the underlying field",
28462        );
28463    }
28464
28465    // ── ci_declared_edge_count — per-`Acao` declared-edge-count axis ─
28466
28467    #[test]
28468    fn ci_declared_edge_count_returns_zero_for_leaf_only_run() {
28469        // The empty-edges arm: a `CiRun` whose every node carries an
28470        // empty `deps` list has zero declared edges. Pins the
28471        // `usize::sum()` accumulator's starting value on the
28472        // no-fan-out shape a `caixa-init`-scaffolded `:kind Acao` a
28473        // caixa's stub `:ci` slot lands as before the author wires
28474        // any `deps`. Fail-before-pass-after guard: pre-lift there was
28475        // no substrate primitive, so an author-scaffolded no-deps run
28476        // would have had its `edge_count = 0` re-derived at every
28477        // consumer site through the same open-coded arithmetic. This
28478        // test now anchors the projection to `ci_declared_edge_count`.
28479        let ci = canteiro_types::CiRun {
28480            workspace: "pleme-io".into(),
28481            repo: "caixa".into(),
28482            nodes: vec![
28483                canteiro_types::CiNode::new(
28484                    "build",
28485                    canteiro_types::EnvClass::None,
28486                    canteiro_types::ActionRef {
28487                        name: "build".into(),
28488                        command: "true".into(),
28489                        args: vec![],
28490                    },
28491                    vec![],
28492                ),
28493                canteiro_types::CiNode::new(
28494                    "lint",
28495                    canteiro_types::EnvClass::None,
28496                    canteiro_types::ActionRef {
28497                        name: "lint".into(),
28498                        command: "true".into(),
28499                        args: vec![],
28500                    },
28501                    vec![],
28502                ),
28503            ],
28504        };
28505        assert_eq!(
28506            ci_declared_edge_count(&ci),
28507            0,
28508            "a two-leaf-node `:ci` run with empty `deps` lists carries \
28509             zero declared edges — the substrate primitive's `usize` \
28510             accumulator must start at zero and pass through untouched",
28511        );
28512    }
28513
28514    #[test]
28515    fn ci_declared_edge_count_returns_deps_sum_across_nodes() {
28516        // The multi-arity arm: a `CiRun` whose nodes carry `deps`
28517        // lists of arities 0/1/2 has declared-edge-count 3 (0+1+2).
28518        // Pins that the substrate primitive routes the sum through
28519        // *every* node's `deps.len()` rather than only the first
28520        // node's (a future regression that collapsed the `map(...)`
28521        // + `sum()` fold onto a `first()` / `next()` shape would
28522        // silently under-count the declared edges — the arity-3
28523        // fixture surfaces it here before the drift lands on the
28524        // `caixa-actions::validate` production `edge_count` artifact).
28525        let ci = canteiro_types::CiRun {
28526            workspace: "pleme-io".into(),
28527            repo: "caixa".into(),
28528            nodes: vec![
28529                canteiro_types::CiNode::new(
28530                    "build",
28531                    canteiro_types::EnvClass::None,
28532                    canteiro_types::ActionRef {
28533                        name: "build".into(),
28534                        command: "true".into(),
28535                        args: vec![],
28536                    },
28537                    vec![],
28538                ),
28539                canteiro_types::CiNode::new(
28540                    "test",
28541                    canteiro_types::EnvClass::None,
28542                    canteiro_types::ActionRef {
28543                        name: "test".into(),
28544                        command: "true".into(),
28545                        args: vec![],
28546                    },
28547                    vec!["build".into()],
28548                ),
28549                canteiro_types::CiNode::new(
28550                    "publish",
28551                    canteiro_types::EnvClass::None,
28552                    canteiro_types::ActionRef {
28553                        name: "publish".into(),
28554                        command: "true".into(),
28555                        args: vec![],
28556                    },
28557                    vec!["build".into(), "test".into()],
28558                ),
28559            ],
28560        };
28561        assert_eq!(
28562            ci_declared_edge_count(&ci),
28563            3,
28564            "declared-edge-count on a 0/1/2-arity node list is the sum \
28565             (0 + 1 + 2 = 3) — the primitive must fold over every node, \
28566             not just the first / last / any-single-index shape",
28567        );
28568    }
28569
28570    #[test]
28571    fn ci_declared_edge_count_counts_edges_before_decompose_gate() {
28572        // The count-is-shape-only arm: an author-declared *cyclic*
28573        // `:ci` run — the exact fixture `decompose_ci` refuses at the
28574        // sibling axis — still carries its declared edge count as a
28575        // property of the *borrowed run's shape*, not of the owned
28576        // `CanteiroDag` `decompose_ci` (would have) returned. Pins
28577        // that a future consumer that wants the declared-edge summary
28578        // *before* running `decompose_ci` (a `feira lint --acao`
28579        // per-caixa pre-flight report that names the declared edge
28580        // count on both accept + reject arms of the sibling
28581        // `decompose_ci` gate) reads a stable count on both arms.
28582        // The two-node cycle `a → b → a` from `cyclic_ci_run()`
28583        // carries exactly 2 declared edges (one per node's singleton
28584        // `deps`), so the primitive returns 2 without ever routing
28585        // through `canteiro_types::decompose`.
28586        let ci = cyclic_ci_run();
28587        assert_eq!(
28588            ci_declared_edge_count(&ci),
28589            2,
28590            "the two-node cycle carries 2 declared `deps` edges (one \
28591             per node's singleton `deps`) — the primitive must read the \
28592             count off the borrowed run's node-list shape, not off the \
28593             `decompose_ci`-produced `CanteiroDag`'s edge algebra",
28594        );
28595    }
28596
28597    #[test]
28598    fn ci_declared_edge_count_matches_open_coded_sum_across_shapes() {
28599        // Byte-parity pin — the three-path convergence discipline
28600        // every peer per-`Acao` substrate primitive carries: the
28601        // primitive's return must equal the open-coded
28602        // `ci.nodes.iter().map(|n| n.deps.len()).sum::<usize>()`
28603        // expression at each of the three canonical `:ci` run shapes
28604        // this test module already carries (`linear_ci_run` — the
28605        // canonical happy-path with one edge, `cyclic_ci_run` — the
28606        // canonical rejected-by-`decompose_ci` shape with two edges,
28607        // and the empty-edges no-fan-out shape the peer
28608        // `ci_declared_edge_count_returns_zero_for_leaf_only_run`
28609        // fixture reads). Any future refactor of the primitive's fold
28610        // shape trips here before landing on the consumer's
28611        // `RenderedAcao::edge_count` artifact.
28612        for (label, ci) in [
28613            ("linear-two-node", linear_ci_run()),
28614            ("cyclic-two-node", cyclic_ci_run()),
28615        ] {
28616            let via_primitive = ci_declared_edge_count(&ci);
28617            let via_open_coded: usize = ci.nodes.iter().map(|n| n.deps.len()).sum();
28618            assert_eq!(
28619                via_primitive, via_open_coded,
28620                "{label}: `ci_declared_edge_count` must equal the \
28621                 open-coded `.nodes.iter().map(|n| n.deps.len()).sum()` \
28622                 the two prior `caixa-actions` open-coded sites carried \
28623                 — pre-lift regression check",
28624            );
28625        }
28626    }
28627
28628    // ── require_single_servico / ServicoCountMismatch — V0 Servico-shape ─
28629
28630    #[test]
28631    fn require_single_servico_accepts_singleton_list() {
28632        // The happy path: the canonical V0 Servico carries exactly one
28633        // `:servicos` entry (the ComputeUnit YAML pointer), the same
28634        // shape every in-tree fixture + canonical example uses. Surfaced
28635        // as `Ok(())` so the renderer's call site reads as a one-liner
28636        // gate beside the peer [`require_kind`] check rather than a
28637        // typed pattern match.
28638        let c = bare_servico();
28639        assert_eq!(
28640            c.servicos.len(),
28641            1,
28642            "fixture pin: bare_servico() is singleton"
28643        );
28644        require_single_servico(&c).unwrap();
28645    }
28646
28647    #[test]
28648    fn require_single_servico_rejects_empty_list_with_typed_mismatch() {
28649        // A Servico-kind caixa with zero `:servicos` entries fails
28650        // `require_single_servico` with a typed [`ServicoCountMismatch`]
28651        // view that names the offending caixa's `:nome` + the actual
28652        // count (0). Pinning the typed shape so a future Display-format
28653        // tweak can't silently drop either of the two load-bearing
28654        // fields (which would regress the "feira verb whose error path
28655        // doesn't name the offending caixa" punch-list item the protocol
28656        // calls out — same shape every peer per-axis lift carries).
28657        let mut c = bare_servico();
28658        c.servicos = vec![];
28659        let err = require_single_servico(&c).unwrap_err();
28660        assert_eq!(err.nome, "hello-rio");
28661        assert_eq!(err.count, 0);
28662    }
28663
28664    #[test]
28665    fn require_single_servico_rejects_multi_entry_list_with_typed_mismatch() {
28666        // The peer arm on the upper-bound axis: a Servico-kind caixa
28667        // with ≥ 2 `:servicos` entries fails the same gate, with the
28668        // typed view carrying the actual count (2). Both empty and
28669        // multi-entry lists land on the same [`ServicoCountMismatch`]
28670        // arm — the V0 contract requires *exactly* one entry, not
28671        // *at-least* one — so the single helper closes both directions
28672        // of the V0 invariant in one call site.
28673        let mut c = bare_servico();
28674        c.servicos = vec![
28675            "servicos/hello-rio.computeunit.yaml".into(),
28676            "servicos/extra.computeunit.yaml".into(),
28677        ];
28678        let err = require_single_servico(&c).unwrap_err();
28679        assert_eq!(err.nome, "hello-rio");
28680        assert_eq!(err.count, 2);
28681    }
28682
28683    #[test]
28684    fn require_single_servico_routes_offending_nome_via_caixa_nome_accessor() {
28685        // Peer to the sibling
28686        // [`require_kind_routes_offending_nome_via_caixa_nome_accessor`]
28687        // pin on the V0 Servico-shape gate's `:nome`-carry axis:
28688        // the [`ServicoCountMismatch::nome`] `String` the constructor
28689        // writes must be a byte-identical copy of what the lifted
28690        // [`crate::Caixa::nome`] accessor returns. Same 9842a4b-shaped
28691        // routing pin the substrate's own [`crate::LayoutInvariants::verify`]
28692        // wrap-envelope emitters carry, extended here to the second of
28693        // the two [`crate::render`]-module typed-view constructor sites
28694        // that carried a raw `caixa.nome.clone()` `String::clone()`
28695        // field access at the pre-converge state.
28696        let mut c = bare_servico();
28697        c.servicos = vec![];
28698        c.nome = "servico-count-pin".into();
28699        let expected_nome_via_accessor = c.nome().to_string();
28700        assert_eq!(
28701            expected_nome_via_accessor, "servico-count-pin",
28702            "the mutated fixture's `:nome` must be observable through \
28703             the accessor before the servico-count gate fires",
28704        );
28705        let err = require_single_servico(&c).unwrap_err();
28706        assert_eq!(
28707            err.nome, expected_nome_via_accessor,
28708            "the ServicoCountMismatch's `nome` field must equal \
28709             `caixa.nome().to_string()` — the typed-view constructor \
28710             must route through the lifted [`Caixa::nome`] accessor's \
28711             `.to_string()` extension, not the raw `caixa.nome.clone()` \
28712             `String::clone()` of the underlying field",
28713        );
28714    }
28715
28716    #[test]
28717    fn servico_count_mismatch_display_names_offending_caixa_nome() {
28718        // The Display impl is the load-bearing surface every renderer's
28719        // `#[error("{0}")] UnsupportedServicoCount(#[from]
28720        // ServicoCountMismatch)` arm prints through. Pinning the exact
28721        // rendered form so a future format change is a one-line edit +
28722        // a one-line test update, not a silent regression of the
28723        // diagnostic clarity that motivated the lift (the prior
28724        // per-renderer `UnsupportedServicoCount(usize)` arm named only
28725        // the count). Same shape every peer [`KindMismatch`] / typed-
28726        // view Display tests pin.
28727        let err = ServicoCountMismatch {
28728            nome: "checkout".into(),
28729            count: 3,
28730        };
28731        let msg = format!("{err}");
28732        assert!(
28733            msg.contains("checkout"),
28734            "Display must name the offending caixa nome (got: {msg:?})"
28735        );
28736        assert!(
28737            msg.contains('3'),
28738            "Display must name the actual count (got: {msg:?})"
28739        );
28740        assert!(
28741            msg.contains(":servicos"),
28742            "Display must name the offending field axis (got: {msg:?})"
28743        );
28744        assert!(
28745            msg.contains("exactly one"),
28746            "Display must name the V0 invariant (got: {msg:?})"
28747        );
28748    }
28749
28750    #[test]
28751    fn overlay_kind_agnostic_for_field_projection() {
28752        // The helper projects fields, not kind — every Caixa carries
28753        // the M2 slot fields by construction. Renderer-level kind
28754        // gates (NotAServico in caixa-helm / caixa-flux) are the
28755        // shape filter; this helper is the field projector. Keeping
28756        // them separate means the same overlay can apply to any
28757        // future per-kind renderer (e.g. when M2.4 supervisor
28758        // rendering acquires its own M2-shaped overlay path).
28759        let mut c = bare_servico();
28760        c.kind = CaixaKind::Biblioteca;
28761        c.servicos = vec![];
28762        c.limits = Some(LimitsSpec {
28763            memory: Some(crate::LIMITS_MEMORY_WASM32_PAGE_BYTES),
28764            ..Default::default()
28765        });
28766        let overlay = servico_m2_overlay(&c).unwrap();
28767        assert!(overlay.contains_key(M2_KEY_LIMITS));
28768    }
28769
28770    // ── require_v0_servico_shape — compound V0-shape entry gate ──────
28771
28772    /// Local `thiserror`-shaped renderer-error stand-in that mirrors the
28773    /// three production callers' shape (`caixa-flux::Error`,
28774    /// `caixa-helm::Error`) at the two `#[from]` variants the compound
28775    /// helper's `E: From<KindMismatch> + From<ServicoCountMismatch>`
28776    /// bound targets. Pinning the shape here so the compound helper's
28777    /// type-inference contract is unit-testable inside caixa-core
28778    /// without a workspace-crate dependency (which would bloat the
28779    /// build graph).
28780    #[derive(Debug, thiserror::Error)]
28781    enum RendererStandIn {
28782        #[error("{0}")]
28783        NotAServico(#[from] KindMismatch),
28784        #[error("{0}")]
28785        UnsupportedServicoCount(#[from] ServicoCountMismatch),
28786    }
28787
28788    #[test]
28789    fn require_v0_servico_shape_accepts_v0_servico() {
28790        // Happy path: a `:kind Servico` caixa with exactly one
28791        // `:servicos` entry — the canonical V0 shape every per-Servico
28792        // renderer's entry-point sees — passes the compound gate. Same
28793        // outcome as the two-line pair the compound helper replaces:
28794        // both predicates surface `Ok(())`, and the compound helper's
28795        // return type carries the caller's `E` inferred from the `?`
28796        // context (unit test uses [`RendererStandIn`] as the stand-in
28797        // for `caixa-flux::Error` / `caixa-helm::Error`).
28798        let c = bare_servico();
28799        let r: Result<(), RendererStandIn> = require_v0_servico_shape(&c);
28800        r.expect("v0 servico shape accepted");
28801    }
28802
28803    #[test]
28804    fn require_v0_servico_shape_forwards_kind_mismatch_first() {
28805        // Order pin: the kind gate fires before the count gate, so a
28806        // `:kind Biblioteca` caixa with zero `:servicos` entries
28807        // surfaces the [`KindMismatch`] arm (the more actionable
28808        // diagnostic — the author has the wrong `:kind`), not the
28809        // [`ServicoCountMismatch`] arm (a downstream consequence of
28810        // the mis-kinded input). Both invariants are violated on this
28811        // input, so the ordering matters — reversing it would flip
28812        // every current caller's diagnostic on a mis-kinded input.
28813        let mut c = bare_servico();
28814        c.kind = CaixaKind::Biblioteca;
28815        c.servicos = vec![];
28816        let err: RendererStandIn = require_v0_servico_shape(&c).unwrap_err();
28817        match err {
28818            RendererStandIn::NotAServico(k) => {
28819                assert_eq!(k.nome, "hello-rio");
28820                assert_eq!(k.expected, CaixaKind::Servico);
28821                assert_eq!(k.actual, CaixaKind::Biblioteca);
28822            }
28823            RendererStandIn::UnsupportedServicoCount(_) => {
28824                panic!("kind gate must fire before count gate on mis-kinded input")
28825            }
28826        }
28827    }
28828
28829    #[test]
28830    fn require_v0_servico_shape_forwards_count_mismatch_on_kind_match() {
28831        // A `:kind Servico` caixa with the wrong `:servicos` count
28832        // (empty or multi-entry) passes the kind gate and lands on the
28833        // [`ServicoCountMismatch`] arm — the same typed view every
28834        // per-renderer `#[from] ServicoCountMismatch` arm already
28835        // surfaces at the two-line pair this helper replaces. Both
28836        // directions of the V0 count invariant (empty AND ≥ 2) land on
28837        // the same arm — pinning the multi-entry direction here; the
28838        // empty direction is covered by the peer
28839        // `require_single_servico_rejects_empty_list_with_typed_mismatch`
28840        // test on the single-axis primitive.
28841        let mut c = bare_servico();
28842        c.servicos = vec![
28843            "servicos/hello-rio.computeunit.yaml".into(),
28844            "servicos/extra.computeunit.yaml".into(),
28845        ];
28846        let err: RendererStandIn = require_v0_servico_shape(&c).unwrap_err();
28847        match err {
28848            RendererStandIn::UnsupportedServicoCount(c) => {
28849                assert_eq!(c.nome, "hello-rio");
28850                assert_eq!(c.count, 2);
28851            }
28852            RendererStandIn::NotAServico(_) => {
28853                panic!("count gate must fire when kind gate passes")
28854            }
28855        }
28856    }
28857
28858    #[test]
28859    fn require_v0_servico_shape_matches_two_line_pair_semantic() {
28860        // Equivalence pin: on every input, the compound helper's
28861        // Ok/Err discrimination matches the two-line pair verbatim —
28862        // the lift is a behavioral no-op at the caller boundary. Peer
28863        // to the sibling `entry_or_default_<variant>` equivalence
28864        // tests that pin the lifted primitive against the inline
28865        // block it replaces.
28866        //
28867        // Three axes covered: V0 shape (Ok/Ok), kind gate fires
28868        // (Err/Ok on the two-line pair — pair short-circuits at the
28869        // kind gate), count gate fires (Ok/Err on the two-line pair —
28870        // pair reaches the count gate).
28871        let cases: Vec<(CaixaKind, Vec<String>)> = vec![
28872            (CaixaKind::Servico, vec!["servicos/x.yaml".into()]),
28873            (CaixaKind::Biblioteca, vec![]),
28874            (CaixaKind::Servico, vec![]),
28875            (CaixaKind::Aplicacao, vec!["servicos/x.yaml".into()]),
28876            (
28877                CaixaKind::Servico,
28878                vec!["servicos/a.yaml".into(), "servicos/b.yaml".into()],
28879            ),
28880        ];
28881        for (kind, servicos) in cases {
28882            let mut c = bare_servico();
28883            c.kind = kind;
28884            c.servicos = servicos;
28885            let pair: Result<(), RendererStandIn> = (|| {
28886                require_kind(&c, CaixaKind::Servico)?;
28887                require_single_servico(&c)?;
28888                Ok(())
28889            })();
28890            let compound: Result<(), RendererStandIn> = require_v0_servico_shape(&c);
28891            assert_eq!(
28892                pair.is_ok(),
28893                compound.is_ok(),
28894                "compound helper must match two-line pair on kind={kind:?} servicos.len()={}",
28895                c.servicos.len(),
28896            );
28897        }
28898    }
28899
28900    // ── require_aplicacao_view — compound per-Aplicacao entry gate ───
28901
28902    /// Local `thiserror`-shaped renderer-error stand-in that mirrors
28903    /// `caixa-mesh::Error`'s two `#[from]` arms at the compound
28904    /// helper's `E: From<KindMismatch> + From<AplicacaoError>` bound.
28905    /// Same discipline as the sibling [`RendererStandIn`] stand-in on
28906    /// the peer per-Servico [`require_v0_servico_shape`] gate: pins
28907    /// the compound helper's type-inference contract inside caixa-core
28908    /// without a workspace-crate dependency (which would bloat the
28909    /// build graph).
28910    #[derive(Debug, thiserror::Error)]
28911    enum AplicacaoRendererStandIn {
28912        #[error("{0}")]
28913        NotAnAplicacao(#[from] KindMismatch),
28914        #[error("{0}")]
28915        InvalidAplicacao(#[from] crate::aplicacao::AplicacaoError),
28916    }
28917
28918    fn bare_aplicacao() -> Caixa {
28919        let mut c = bare_servico();
28920        c.nome = "checkout".into();
28921        c.kind = CaixaKind::Aplicacao;
28922        c.servicos = vec![];
28923        c.membros = vec![
28924            crate::aplicacao::Membro {
28925                caixa: "cart".into(),
28926                versao: "^0.1".into(),
28927            },
28928            crate::aplicacao::Membro {
28929                caixa: "catalog".into(),
28930                versao: "^0.1".into(),
28931            },
28932        ];
28933        // `:placement` needs at least one named cluster (every strategy
28934        // uses the list as a hosting/takeover/shard pool per
28935        // MESH-COMPOSITION §II.1/§II.4); the fold-through
28936        // [`Caixa::aplicacao_view`] uses `Placement::default()` which
28937        // carries an empty `:clusters` and would trip
28938        // `AplicacaoError::PlacementWithoutClusters` at
28939        // `AplicacaoSpec::validate` — the peer per-Aplicacao
28940        // renderer fixtures (`caixa-mesh::aplicacao_caixa`) pin the
28941        // same non-empty `:clusters` shape.
28942        c.placement = Some(crate::aplicacao::Placement {
28943            estrategia: crate::aplicacao::PlacementStrategy::SingleNode,
28944            clusters: vec!["default".into()],
28945            affinity: None,
28946            shard_key: None,
28947        });
28948        c
28949    }
28950
28951    #[test]
28952    fn require_aplicacao_view_accepts_valid_aplicacao() {
28953        // Happy path: a `:kind Aplicacao` caixa with a well-formed
28954        // `:membros` stanza — the canonical V0 shape every
28955        // per-Aplicacao renderer's entry-point sees — passes the
28956        // compound three-arm gate and returns a validated
28957        // [`AplicacaoSpec`]. Same outcome as the three-line cascade
28958        // the compound helper replaces: [`require_kind`] passes,
28959        // [`Caixa::aplicacao_view`] returns `Some(spec)`, and
28960        // [`AplicacaoSpec::validate`] passes. Peer to
28961        // `require_v0_servico_shape_accepts_v0_servico` on the
28962        // sibling per-Servico compound gate.
28963        let c = bare_aplicacao();
28964        let spec: crate::aplicacao::AplicacaoSpec =
28965            require_aplicacao_view::<AplicacaoRendererStandIn>(&c)
28966                .expect("valid aplicacao shape accepted");
28967        assert_eq!(spec.membros.len(), 2);
28968        assert_eq!(spec.membros[0].caixa, "cart");
28969        assert_eq!(spec.membros[1].caixa, "catalog");
28970    }
28971
28972    #[test]
28973    fn require_aplicacao_view_forwards_kind_mismatch_first() {
28974        // Order pin: the kind gate fires before the aplicacao_view
28975        // fold-in + [`AplicacaoSpec::validate`], so a `:kind Servico`
28976        // caixa carrying a well-formed `:membros` stanza (the manifest
28977        // field's documented "silently ignored" case on a non-Aplicacao
28978        // kind) surfaces the [`KindMismatch`] arm — the more actionable
28979        // diagnostic — rather than any spec-side arm the manifest
28980        // author never intended to hit. Reversing the order would flip
28981        // every current caller's diagnostic on a mis-kinded input.
28982        // Peer to `require_v0_servico_shape_forwards_kind_mismatch_first`
28983        // on the sibling per-Servico compound gate.
28984        let mut c = bare_aplicacao();
28985        c.kind = CaixaKind::Servico;
28986        c.servicos = vec!["servicos/hello.computeunit.yaml".into()];
28987        let err: AplicacaoRendererStandIn = require_aplicacao_view(&c).unwrap_err();
28988        match err {
28989            AplicacaoRendererStandIn::NotAnAplicacao(k) => {
28990                assert_eq!(k.nome, "checkout");
28991                assert_eq!(k.expected, CaixaKind::Aplicacao);
28992                assert_eq!(k.actual, CaixaKind::Servico);
28993            }
28994            AplicacaoRendererStandIn::InvalidAplicacao(_) => {
28995                panic!("kind gate must fire before aplicacao-view fold-in on mis-kinded input")
28996            }
28997        }
28998    }
28999
29000    #[test]
29001    fn require_aplicacao_view_forwards_aplicacao_error_on_kind_match() {
29002        // A `:kind Aplicacao` caixa that passes the kind gate but
29003        // fails [`AplicacaoSpec::validate`] (empty `:membros` here —
29004        // the [`AplicacaoError::NoMembros`] arm every Aplicacao must
29005        // satisfy per MESH-COMPOSITION §III.1) lands on the
29006        // [`AplicacaoError`] arm through the compound helper's
29007        // `E: From<AplicacaoError>` bound. Same diagnostic the
29008        // three-line cascade the compound helper replaces surfaces at
29009        // `spec.validate()?`. Peer to
29010        // `require_v0_servico_shape_forwards_count_mismatch_on_kind_match`
29011        // on the sibling per-Servico compound gate.
29012        let mut c = bare_aplicacao();
29013        c.membros = vec![]; // trips AplicacaoError::NoMembros
29014        let err: AplicacaoRendererStandIn = require_aplicacao_view(&c).unwrap_err();
29015        match err {
29016            AplicacaoRendererStandIn::InvalidAplicacao(
29017                crate::aplicacao::AplicacaoError::NoMembros,
29018            ) => {}
29019            AplicacaoRendererStandIn::InvalidAplicacao(other) => {
29020                panic!("expected NoMembros arm, got {other:?}")
29021            }
29022            AplicacaoRendererStandIn::NotAnAplicacao(_) => {
29023                panic!("spec-validate arm must fire when kind gate passes")
29024            }
29025        }
29026    }
29027
29028    #[test]
29029    fn require_aplicacao_view_matches_three_line_cascade_semantic() {
29030        // Equivalence pin: on every input, the compound helper's
29031        // Ok/Err discrimination matches the three-line cascade
29032        // verbatim — the lift is a behavioral no-op at the caller
29033        // boundary. Peer to the sibling
29034        // `require_v0_servico_shape_matches_two_line_pair_semantic`
29035        // equivalence pin on the per-Servico compound gate.
29036        //
29037        // Four axes covered: Aplicacao shape (Ok/Ok), kind gate fires
29038        // (Err/Ok on the cascade — cascade short-circuits at the kind
29039        // gate), spec-validate arm fires (Ok/Err on the cascade —
29040        // cascade reaches [`AplicacaoSpec::validate`]), and a
29041        // mis-kinded caixa with a spec-invalid `:membros` stanza (both
29042        // invariants violated — the kind gate must still fire first).
29043        let cases: Vec<(CaixaKind, Vec<crate::aplicacao::Membro>)> = vec![
29044            (
29045                CaixaKind::Aplicacao,
29046                vec![
29047                    crate::aplicacao::Membro {
29048                        caixa: "cart".into(),
29049                        versao: "^0.1".into(),
29050                    },
29051                    crate::aplicacao::Membro {
29052                        caixa: "catalog".into(),
29053                        versao: "^0.1".into(),
29054                    },
29055                ],
29056            ),
29057            (CaixaKind::Servico, vec![]),
29058            (CaixaKind::Aplicacao, vec![]),
29059            (
29060                CaixaKind::Biblioteca,
29061                vec![crate::aplicacao::Membro {
29062                    caixa: "cart".into(),
29063                    versao: "^0.1".into(),
29064                }],
29065            ),
29066        ];
29067        for (kind, membros) in cases {
29068            let mut c = bare_aplicacao();
29069            c.kind = kind;
29070            c.membros = membros.clone();
29071            if kind == CaixaKind::Servico {
29072                c.servicos = vec!["servicos/hello.computeunit.yaml".into()];
29073            } else {
29074                c.servicos = vec![];
29075            }
29076            let cascade: Result<crate::aplicacao::AplicacaoSpec, AplicacaoRendererStandIn> =
29077                (|| {
29078                    require_kind(&c, CaixaKind::Aplicacao)?;
29079                    let spec = c.aplicacao_view().expect(
29080                        "require_kind(Aplicacao) guarantees Caixa::aplicacao_view returns Some",
29081                    );
29082                    spec.validate()?;
29083                    Ok(spec)
29084                })();
29085            let compound: Result<crate::aplicacao::AplicacaoSpec, AplicacaoRendererStandIn> =
29086                require_aplicacao_view(&c);
29087            assert_eq!(
29088                cascade.is_ok(),
29089                compound.is_ok(),
29090                "compound helper must match three-line cascade on kind={kind:?} membros.len()={}",
29091                membros.len(),
29092            );
29093            // Compound helper's Ok-arm return matches cascade's
29094            // Ok-arm return byte-for-byte (via serde YAML round-trip
29095            // — the `AplicacaoSpec` derives `Serialize`, so equal-
29096            // rendering values are the substrate-canonical equality
29097            // signal the peer downstream renderers key off).
29098            if let (Ok(cascade_spec), Ok(compound_spec)) = (cascade, compound) {
29099                assert_eq!(
29100                    serde_yaml::to_string(&cascade_spec).expect("cascade AplicacaoSpec serializes"),
29101                    serde_yaml::to_string(&compound_spec)
29102                        .expect("compound AplicacaoSpec serializes"),
29103                    "compound helper's Ok arm must return byte-equal AplicacaoSpec to cascade"
29104                );
29105            }
29106        }
29107    }
29108
29109    // ── require_acao_view — compound per-`Acao` entry gate ───────────
29110
29111    /// Local `thiserror`-shaped renderer-error stand-in that mirrors
29112    /// `caixa-actions::Error`'s three `#[from]` arms at the compound
29113    /// helper's `E: From<KindMismatch> + From<MissingCiSlot> +
29114    /// From<CiDecomposeFailure>` bound. Same discipline as the sibling
29115    /// [`RendererStandIn`] / [`AplicacaoRendererStandIn`] stand-ins on
29116    /// the peer per-Servico [`require_v0_servico_shape`] and
29117    /// per-Aplicacao [`require_aplicacao_view`] compound gates: pins
29118    /// the compound helper's type-inference contract inside caixa-core
29119    /// without a workspace-crate dependency (which would bloat the
29120    /// build graph).
29121    #[derive(Debug, thiserror::Error)]
29122    enum AcaoRendererStandIn {
29123        #[error("{0}")]
29124        NotAnAcao(#[from] KindMismatch),
29125        #[error("{0}")]
29126        MissingCi(#[from] MissingCiSlot),
29127        #[error("{0}")]
29128        Decompose(#[from] CiDecomposeFailure),
29129    }
29130
29131    #[test]
29132    fn require_acao_view_accepts_valid_acao() {
29133        // Happy path: a `:kind Acao` caixa with a well-formed `:ci`
29134        // stanza — the canonical V0 shape every per-`Acao` consumer's
29135        // entry-point sees — passes the compound three-arm gate and
29136        // returns the borrowed [`canteiro_types::CiRun`] paired with
29137        // the owned [`canteiro_types::CanteiroDag`] the substrate
29138        // primitive produced. Same outcome as the three-line prelude
29139        // the compound helper replaces: [`require_kind`] passes,
29140        // [`require_ci`] returns the borrowed slot, [`decompose_ci`]
29141        // accepts the run. Peer to
29142        // `require_aplicacao_view_accepts_valid_aplicacao` and
29143        // `require_v0_servico_shape_accepts_v0_servico` on the sibling
29144        // per-Aplicacao / per-Servico compound gates.
29145        let mut c = bare_acao_without_ci();
29146        c.ci = Some(linear_ci_run());
29147        let (ci, cd) = require_acao_view::<AcaoRendererStandIn>(&c)
29148            .expect("valid Acao shape accepted by compound helper");
29149        assert_eq!(ci.workspace, "pleme-io");
29150        assert_eq!(ci.nodes.len(), 2);
29151        // `topo_order()` is infallible on the DAG the compound helper
29152        // returns, mirroring the substrate-side pass-through pin at
29153        // [`decompose_ci_accepts_valid_ci_run_and_returns_canteiro_dag`].
29154        let topo = cd
29155            .topo_order()
29156            .expect("acyclic CanteiroDag returns a valid topo_order");
29157        assert_eq!(
29158            topo.iter().count(),
29159            2,
29160            "topo_order on the compound helper's returned DAG must yield \
29161             two node ids on a two-node acyclic run"
29162        );
29163    }
29164
29165    #[test]
29166    fn require_acao_view_forwards_kind_mismatch_first() {
29167        // Order pin: the kind gate fires before the presence gate + the
29168        // decompose gate, so a `:kind Servico` caixa carrying a
29169        // well-formed `:ci` stanza (the manifest field's documented
29170        // "silently ignored" case on a non-`Acao` kind) surfaces the
29171        // [`KindMismatch`] arm — the more actionable diagnostic —
29172        // rather than either downstream arm the manifest author never
29173        // intended to hit. Reversing the order would flip every
29174        // current caller's diagnostic on a mis-kinded input. Peer to
29175        // `require_aplicacao_view_forwards_kind_mismatch_first` and
29176        // `require_v0_servico_shape_forwards_kind_mismatch_first` on
29177        // the sibling per-Aplicacao / per-Servico compound gates.
29178        let mut c = bare_acao_without_ci();
29179        c.kind = CaixaKind::Servico;
29180        c.servicos = vec!["servicos/hello.computeunit.yaml".into()];
29181        c.ci = Some(linear_ci_run());
29182        // `unwrap_err()` needs `T: Debug`, and the Ok half here carries
29183        // `canteiro_types::CanteiroDag`, which does not derive it at the
29184        // pinned sui rev — so the whole caixa-core test target failed to
29185        // COMPILE. A let-else says the same thing without borrowing a
29186        // bound from a foreign type we do not own.
29187        let Err(err): Result<_, AcaoRendererStandIn> = require_acao_view(&c) else {
29188            panic!("this fixture must not produce an Acao view");
29189        };
29190        match err {
29191            AcaoRendererStandIn::NotAnAcao(k) => {
29192                assert_eq!(k.nome, "hello-rio");
29193                assert_eq!(k.expected, CaixaKind::Acao);
29194                assert_eq!(k.actual, CaixaKind::Servico);
29195            }
29196            AcaoRendererStandIn::MissingCi(_) => {
29197                panic!("kind gate must fire before presence gate on mis-kinded input")
29198            }
29199            AcaoRendererStandIn::Decompose(_) => {
29200                panic!("kind gate must fire before decompose gate on mis-kinded input")
29201            }
29202        }
29203    }
29204
29205    #[test]
29206    fn require_acao_view_forwards_missing_ci_slot_on_kind_match() {
29207        // A `:kind Acao` caixa that passes the kind gate but declares
29208        // no `:ci` slot lands on the [`MissingCiSlot`] arm through the
29209        // compound helper's `E: From<MissingCiSlot>` bound — the same
29210        // typed view the peer [`require_ci`] presence gate produces at
29211        // the single-axis primitive, propagated through the compound
29212        // gate's second arm.
29213        let c = bare_acao_without_ci();
29214        // `unwrap_err()` needs `T: Debug`, and the Ok half here carries
29215        // `canteiro_types::CanteiroDag`, which does not derive it at the
29216        // pinned sui rev — so the whole caixa-core test target failed to
29217        // COMPILE. A let-else says the same thing without borrowing a
29218        // bound from a foreign type we do not own.
29219        let Err(err): Result<_, AcaoRendererStandIn> = require_acao_view(&c) else {
29220            panic!("this fixture must not produce an Acao view");
29221        };
29222        match err {
29223            AcaoRendererStandIn::MissingCi(m) => {
29224                assert_eq!(m.nome, "hello-rio");
29225            }
29226            AcaoRendererStandIn::NotAnAcao(_) => {
29227                panic!("presence gate must fire when kind gate passes")
29228            }
29229            AcaoRendererStandIn::Decompose(_) => {
29230                panic!("presence gate must fire before decompose gate on missing `:ci` input")
29231            }
29232        }
29233    }
29234
29235    #[test]
29236    fn require_acao_view_forwards_decompose_failure_on_ci_present() {
29237        // A `:kind Acao` caixa that passes the kind + presence gates
29238        // but carries a cyclic `:ci` run lands on the
29239        // [`CiDecomposeFailure`] arm through the compound helper's
29240        // `E: From<CiDecomposeFailure>` bound — the same typed view
29241        // the peer [`decompose_ci`] gate produces at the single-axis
29242        // primitive, propagated through the compound gate's third
29243        // arm.
29244        let mut c = bare_acao_without_ci();
29245        c.ci = Some(cyclic_ci_run());
29246        // `unwrap_err()` needs `T: Debug`, and the Ok half here carries
29247        // `canteiro_types::CanteiroDag`, which does not derive it at the
29248        // pinned sui rev — so the whole caixa-core test target failed to
29249        // COMPILE. A let-else says the same thing without borrowing a
29250        // bound from a foreign type we do not own.
29251        let Err(err): Result<_, AcaoRendererStandIn> = require_acao_view(&c) else {
29252            panic!("this fixture must not produce an Acao view");
29253        };
29254        match err {
29255            AcaoRendererStandIn::Decompose(f) => {
29256                assert_eq!(f.nome, "hello-rio");
29257                assert_eq!(f.source, canteiro_types::DecomposeError::Cycle);
29258            }
29259            AcaoRendererStandIn::NotAnAcao(_) => {
29260                panic!("decompose gate must fire when kind + presence gates pass")
29261            }
29262            AcaoRendererStandIn::MissingCi(_) => {
29263                panic!("decompose gate must fire when presence gate passes")
29264            }
29265        }
29266    }
29267
29268    #[test]
29269    fn require_acao_view_matches_three_line_prelude_semantic() {
29270        // Equivalence pin: on every input, the compound helper's
29271        // Ok/Err discrimination matches the three-line prelude
29272        // verbatim — the lift is a behavioral no-op at the caller
29273        // boundary. Peer to the sibling
29274        // `require_aplicacao_view_matches_three_line_cascade_semantic`
29275        // and `require_v0_servico_shape_matches_two_line_pair_semantic`
29276        // equivalence pins on the per-Aplicacao / per-Servico compound
29277        // gates.
29278        //
29279        // Five axes covered: valid Acao (Ok/Ok), kind gate fires
29280        // (Err/Err on the prelude — prelude short-circuits at the kind
29281        // gate), presence gate fires (Ok/Err on the prelude — prelude
29282        // reaches [`require_ci`]), decompose gate fires (Ok/Err on the
29283        // prelude — prelude reaches [`decompose_ci`]), and a
29284        // mis-kinded caixa with a well-formed `:ci` (both invariants
29285        // relevant — the kind gate must still fire first).
29286        let cases: Vec<(CaixaKind, Option<canteiro_types::CiRun>)> = vec![
29287            (CaixaKind::Acao, Some(linear_ci_run())),
29288            (CaixaKind::Servico, Some(linear_ci_run())),
29289            (CaixaKind::Acao, None),
29290            (CaixaKind::Acao, Some(cyclic_ci_run())),
29291            (CaixaKind::Biblioteca, None),
29292        ];
29293        for (kind, ci) in cases {
29294            let mut c = bare_acao_without_ci();
29295            c.kind = kind;
29296            c.ci = ci.clone();
29297            if kind == CaixaKind::Servico {
29298                c.servicos = vec!["servicos/hello.computeunit.yaml".into()];
29299            } else {
29300                c.servicos = vec![];
29301            }
29302            let prelude: Result<
29303                (&canteiro_types::CiRun, canteiro_types::CanteiroDag),
29304                AcaoRendererStandIn,
29305            > = (|| {
29306                require_kind(&c, CaixaKind::Acao)?;
29307                let ci_borrowed = require_ci(&c)?;
29308                let cd = decompose_ci(&c, ci_borrowed)?;
29309                Ok((ci_borrowed, cd))
29310            })();
29311            let compound: Result<
29312                (&canteiro_types::CiRun, canteiro_types::CanteiroDag),
29313                AcaoRendererStandIn,
29314            > = require_acao_view(&c);
29315            assert_eq!(
29316                prelude.is_ok(),
29317                compound.is_ok(),
29318                "compound helper must match three-line prelude on kind={kind:?} ci.is_some()={}",
29319                ci.is_some(),
29320            );
29321            // Compound helper's Ok-arm return matches prelude's
29322            // Ok-arm return byte-for-byte on both projections: the
29323            // borrowed `&CiRun`'s node count + workspace / repo
29324            // identity, and the owned `CanteiroDag`'s
29325            // topological-order node-name projection (the substrate-
29326            // canonical equality signal every downstream per-`Acao`
29327            // consumer keys off).
29328            if let (Ok((prelude_ci, prelude_cd)), Ok((compound_ci, compound_cd))) =
29329                (prelude, compound)
29330            {
29331                assert_eq!(
29332                    prelude_ci.workspace, compound_ci.workspace,
29333                    "compound helper's borrowed CiRun's workspace must \
29334                     equal prelude's byte-for-byte"
29335                );
29336                assert_eq!(
29337                    prelude_ci.repo, compound_ci.repo,
29338                    "compound helper's borrowed CiRun's repo must equal \
29339                     prelude's byte-for-byte"
29340                );
29341                assert_eq!(
29342                    prelude_ci.nodes.len(),
29343                    compound_ci.nodes.len(),
29344                    "compound helper's borrowed CiRun's node count must \
29345                     equal prelude's"
29346                );
29347                let prelude_topo = prelude_cd
29348                    .topo_order()
29349                    .expect("prelude's DAG produces a valid topo_order");
29350                let compound_topo = compound_cd
29351                    .topo_order()
29352                    .expect("compound's DAG produces a valid topo_order");
29353                let prelude_names: Vec<String> = prelude_topo
29354                    .iter()
29355                    .filter_map(|id| prelude_cd.nodes.get(id).map(|n| n.name.clone()))
29356                    .collect();
29357                let compound_names: Vec<String> = compound_topo
29358                    .iter()
29359                    .filter_map(|id| compound_cd.nodes.get(id).map(|n| n.name.clone()))
29360                    .collect();
29361                assert_eq!(
29362                    prelude_names, compound_names,
29363                    "compound helper's DAG must produce byte-equal \
29364                     topological-order node-name projection to prelude's"
29365                );
29366            }
29367        }
29368    }
29369
29370    // ── single_field_overlay — typed per-axis overlay primitive ──────────
29371
29372    #[test]
29373    fn single_field_overlay_none_yields_none() {
29374        // Empty-axis-skip semantic at the typed-primitive layer: a
29375        // `None` slot returns `None`, not `Some(empty Mapping)`. The
29376        // caller's `if let Some(overlay) = …` guard then becomes the
29377        // single emission gate, and a malformed `outer: {}` (the
29378        // empty-mapping form some K8s parsers reject) is structurally
29379        // impossible by construction.
29380        let v: Option<serde_yaml::Value> = single_field_overlay::<u32, _>(None, "attempts", |n| {
29381            serde_yaml::Value::Number(n.into())
29382        });
29383        assert!(v.is_none());
29384    }
29385
29386    #[test]
29387    fn single_field_overlay_some_yields_single_field_mapping() {
29388        // The Some arm builds exactly one inner key/value pair, no
29389        // more, no less. Pinning the shape so a future refactor can't
29390        // accidentally introduce a second field (which would render
29391        // as a malformed `timeouts: { request: "30s", <leak>: ... }`
29392        // overlay block).
29393        let v = single_field_overlay(Some(30u32), "attempts", |n| {
29394            serde_yaml::Value::Number(n.into())
29395        })
29396        .expect("Some arm yields Some(...)");
29397        let m = v.as_mapping().expect("mapping shape");
29398        assert_eq!(m.len(), 1);
29399        assert_eq!(m.get("attempts").and_then(|x| x.as_u64()), Some(30));
29400    }
29401
29402    #[test]
29403    fn single_field_overlay_threads_typed_value_through_closure() {
29404        // The closure receives the unwrapped typed `T` (not the
29405        // wrapping `Option<T>`), so the per-overlay value-shaping
29406        // logic stays at the call site. Three different Value shapes
29407        // pin the closure's type-flow: a `String` (for canonical
29408        // duration / enum scalars), a `Number` (for typed integer
29409        // attempt counts), and a derived `Bool` (for tristate enums).
29410        // Mirrors the three landed overlays' shapes letter-for-letter.
29411        let dur = single_field_overlay(Some("30s".to_string()), "request", |s| {
29412            serde_yaml::Value::String(s)
29413        })
29414        .unwrap();
29415        assert_eq!(dur.get("request").and_then(|v| v.as_str()), Some("30s"));
29416
29417        let num = single_field_overlay(Some(3u32), "attempts", |n| {
29418            serde_yaml::Value::Number(n.into())
29419        })
29420        .unwrap();
29421        assert_eq!(num.get("attempts").and_then(|v| v.as_u64()), Some(3));
29422
29423        // The mtls tristate's two non-None arms map to enum strings,
29424        // not raw bools (the Cilium CRD's `mode: required|disabled`
29425        // shape — pinned end-to-end at every emit site by the
29426        // `cnp_authentication_mode_serialized_as_yaml_string` test).
29427        // Both scalar-values thread through the lifted canonical
29428        // [`cilium_auth_mode`] bijection — the same `bool → &'static
29429        // str` projection the production `cilium_network_policies`
29430        // per-`(:de, :para)` overlay closure reaches for, so a future
29431        // Cilium CNP `MutualAuthenticationMode` OpenAPI schema enum
29432        // rebrand (either arm's scalar-value string, or the per-arm
29433        // dispatch) lands at the two consts + one projection body
29434        // rather than duplicated across the production emitter site
29435        // and this generic-helper pin.
29436        let mode = single_field_overlay(Some(true), CILIUM_KEY_MODE, |b| {
29437            serde_yaml::Value::String(cilium_auth_mode(b).into())
29438        })
29439        .unwrap();
29440        assert_eq!(
29441            mode.get(CILIUM_KEY_MODE).and_then(|v| v.as_str()),
29442            Some(CILIUM_AUTH_MODE_REQUIRED)
29443        );
29444    }
29445
29446    #[test]
29447    fn single_field_overlay_outer_key_is_callers_concern() {
29448        // The helper builds the *inner* (single-field) Mapping; the
29449        // *outer* key (`timeouts` / `retry` / `authentication`) is
29450        // the caller's `if let Some(overlay) = … { rule.insert(<outer>,
29451        // overlay.clone()) }` insertion. Pinning that the helper's
29452        // returned Value carries no outer-key wrapping — emitting the
29453        // outer-key-wrapped form here would silently double-wrap
29454        // every overlay (`timeouts: { timeouts: { request: "30s" } }`
29455        // post-insertion).
29456        let v = single_field_overlay(Some(30u32), "attempts", |n| {
29457            serde_yaml::Value::Number(n.into())
29458        })
29459        .unwrap();
29460        let m = v.as_mapping().unwrap();
29461        // Only the inner key — no `timeouts:` / `retry:` /
29462        // `authentication:` wrapper at this layer.
29463        for k in ["timeouts", "retry", "authentication"] {
29464            assert!(
29465                m.get(k).is_none(),
29466                "single_field_overlay must not pre-insert the outer key {k:?} \
29467                 (the caller's per-rule insert is the canonical insertion site)"
29468            );
29469        }
29470    }
29471
29472    #[test]
29473    fn single_field_overlay_value_is_clonable_for_per_rule_dispatch() {
29474        // The build-once-clone-many idiom every emit-site uses: the
29475        // overlay is computed once per renderer call (so the closure
29476        // runs exactly once) and `.clone()`d into each rule of the
29477        // emitted sequence. Pin that the returned Value is in fact
29478        // cloneable (a `serde_yaml::Value` always is, but the test
29479        // pins the contract end-to-end so a future refactor that
29480        // returns a non-Cloneable wrapper surfaces here).
29481        let v = single_field_overlay(Some(30u32), "attempts", |n| {
29482            serde_yaml::Value::Number(n.into())
29483        })
29484        .unwrap();
29485        let v_clone = v.clone();
29486        assert_eq!(v, v_clone);
29487    }
29488
29489    // ── upsert_named_entry — typed sequence-upsert primitive ─────────────
29490
29491    #[test]
29492    fn upsert_named_entry_appends_when_empty() {
29493        // Empty-sequence-first arm: an initially-empty aggregator
29494        // programs.yaml carries no matching entry, so the upsert falls
29495        // through to the append-new tail and returns
29496        // `Ok(true)` (newly inserted). Pins the append-new contract
29497        // both writer-side [`caixa_flux`] upsert paths lean on when
29498        // the aggregator's `programs:` sequence is empty
29499        // (`upsert_inserts_new_entry` at the values.yaml layer,
29500        // `upsert_helmrelease_inserts_under_spec_values_programs` at
29501        // the HelmRelease layer) — the same shape at the typed-
29502        // primitive layer as the two production sites.
29503        let mut arr: Vec<serde_yaml::Value> = Vec::new();
29504        let entry: serde_yaml::Value =
29505            serde_yaml::from_str("{ name: hello-rio, module: { source: oci://x } }").unwrap();
29506        let inserted =
29507            upsert_named_entry::<()>(&mut arr, entry, FLEET_PROGRAMS_KEY_NAME, || ()).unwrap();
29508        assert!(inserted, "empty sequence + new entry must append");
29509        assert_eq!(arr.len(), 1);
29510        assert_eq!(
29511            arr[0].get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()),
29512            Some("hello-rio")
29513        );
29514    }
29515
29516    #[test]
29517    fn upsert_named_entry_appends_when_no_match() {
29518        // Non-matching-name append arm: an aggregator sequence with a
29519        // differently-named entry carries no matching name-key value,
29520        // so the upsert falls through to the append-new tail (never
29521        // replacing) and returns `Ok(true)`. Pins the append-only
29522        // semantic that keeps every unrelated entry untouched.
29523        let mut arr: Vec<serde_yaml::Value> = vec![
29524            serde_yaml::from_str("{ name: other, module: { source: github:foo/bar } }").unwrap(),
29525        ];
29526        let entry: serde_yaml::Value =
29527            serde_yaml::from_str("{ name: hello-rio, module: { source: oci://x } }").unwrap();
29528        let inserted =
29529            upsert_named_entry::<()>(&mut arr, entry, FLEET_PROGRAMS_KEY_NAME, || ()).unwrap();
29530        assert!(inserted);
29531        assert_eq!(arr.len(), 2);
29532        assert_eq!(
29533            arr[0].get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()),
29534            Some("other")
29535        );
29536        assert_eq!(
29537            arr[1].get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()),
29538            Some("hello-rio")
29539        );
29540    }
29541
29542    #[test]
29543    fn upsert_named_entry_replaces_when_match() {
29544        // Match-and-replace arm: an aggregator sequence carrying an
29545        // entry whose `<name_key>` matches the new entry's name-scalar
29546        // gets its slot rewritten in place and the helper returns
29547        // `Ok(false)` (replaced-not-appended). Pins the idempotency
29548        // contract every writer-side upsert path lands on — the same
29549        // caixa.lisp deployed twice must upsert to the same
29550        // aggregator entry, never grow a duplicated `programs[]`
29551        // entry. Peer at the substrate layer with the two production
29552        // `upsert_replaces_existing_entry` /
29553        // `upsert_helmrelease_replaces_existing` tests
29554        // ([`caixa_flux`]).
29555        let mut arr: Vec<serde_yaml::Value> = vec![
29556            serde_yaml::from_str("{ name: hello-rio, module: { source: oci://old } }").unwrap(),
29557        ];
29558        let entry: serde_yaml::Value =
29559            serde_yaml::from_str("{ name: hello-rio, module: { source: oci://new } }").unwrap();
29560        let inserted =
29561            upsert_named_entry::<()>(&mut arr, entry, FLEET_PROGRAMS_KEY_NAME, || ()).unwrap();
29562        assert!(!inserted, "matching name must replace, not append");
29563        assert_eq!(arr.len(), 1);
29564        assert_eq!(
29565            arr[0]
29566                .get(COMPUTEUNIT_SPEC_KEY_MODULE)
29567                .and_then(|m| m.get(COMPUTEUNIT_MODULE_KEY_SOURCE))
29568                .and_then(|s| s.as_str()),
29569            Some("oci://new")
29570        );
29571    }
29572
29573    #[test]
29574    fn upsert_named_entry_preserves_position_on_replace() {
29575        // Position-preserving-replace pin: when an interior entry
29576        // matches, its slot is rewritten in place and the surrounding
29577        // entries stay put (first / last / any middle position). The
29578        // aggregator's fanout consumers filter `programs[]` in
29579        // declaration order (the `lareira-fleet-programs` chart's
29580        // `.Values.programs` iteration + the future
29581        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
29582        // per-entry admission bind); a replace-then-move-to-tail shift
29583        // (silently promoting the just-upserted entry to end-of-list)
29584        // would silently reorder every downstream consumer's iteration
29585        // window. Same declaration-order-preservation contract the
29586        // aggregator side relies on.
29587        let mut arr: Vec<serde_yaml::Value> = vec![
29588            serde_yaml::from_str("{ name: alpha, module: { source: github:a/a } }").unwrap(),
29589            serde_yaml::from_str("{ name: beta, module: { source: github:b/old } }").unwrap(),
29590            serde_yaml::from_str("{ name: gamma, module: { source: github:g/g } }").unwrap(),
29591        ];
29592        let entry: serde_yaml::Value =
29593            serde_yaml::from_str("{ name: beta, module: { source: github:b/new } }").unwrap();
29594        let inserted =
29595            upsert_named_entry::<()>(&mut arr, entry, FLEET_PROGRAMS_KEY_NAME, || ()).unwrap();
29596        assert!(!inserted);
29597        assert_eq!(arr.len(), 3);
29598        // Order pin: alpha stays at 0, beta stays at 1 (rewritten),
29599        // gamma stays at 2 — replace must preserve position.
29600        let names: Vec<&str> = arr
29601            .iter()
29602            .filter_map(|v| v.get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()))
29603            .collect();
29604        assert_eq!(names, ["alpha", "beta", "gamma"]);
29605        assert_eq!(
29606            arr[1]
29607                .get(COMPUTEUNIT_SPEC_KEY_MODULE)
29608                .and_then(|m| m.get(COMPUTEUNIT_MODULE_KEY_SOURCE))
29609                .and_then(|s| s.as_str()),
29610            Some("github:b/new")
29611        );
29612    }
29613
29614    #[test]
29615    fn upsert_named_entry_calls_error_closure_on_missing_name_key() {
29616        // Missing-name-scalar arm: when the new entry doesn't carry
29617        // `<name_key>` as a string scalar, the helper calls the
29618        // caller's `on_missing_name` closure — the caller's own typed
29619        // [`crate::RenderError`]-shaped error surface remains
29620        // authoritative. Threaded through a closure so this crate
29621        // stays agnostic to the caller's error enum shape (the two
29622        // production sites in [`caixa_flux`] surface
29623        // `Error::MissingField(FLEET_PROGRAMS_KEY_NAME)` verbatim,
29624        // and any future upsert path — the M4
29625        // `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
29626        // per-entry upsert, the `caixa-otel` per-scrape upsert —
29627        // surfaces its own typed variant).
29628        let mut arr: Vec<serde_yaml::Value> = Vec::new();
29629        let entry: serde_yaml::Value =
29630            serde_yaml::from_str("{ module: { source: oci://x } }").unwrap();
29631        let err = upsert_named_entry(&mut arr, entry, FLEET_PROGRAMS_KEY_NAME, || {
29632            "missing-name".to_string()
29633        })
29634        .unwrap_err();
29635        assert_eq!(err, "missing-name");
29636        assert!(arr.is_empty(), "missing-name entry must not land in arr");
29637    }
29638
29639    #[test]
29640    fn upsert_named_entry_calls_error_closure_on_non_string_name_scalar() {
29641        // Non-string-name-scalar arm: when the new entry's
29642        // `<name_key>` is present but not a string (a number, a
29643        // mapping, a sequence — the paste-from-binary footgun where
29644        // an author or a schema-migration script accidentally lands a
29645        // JSON-Number in the name slot), the helper takes the same
29646        // path as the missing-name arm and calls the caller's
29647        // `on_missing_name` closure. Peer arm to the
29648        // upsert_named_entry_calls_error_closure_on_missing_name_key
29649        // pin — both non-string-scalar paths route through the same
29650        // caller-owned diagnostic.
29651        let mut arr: Vec<serde_yaml::Value> = Vec::new();
29652        let entry: serde_yaml::Value =
29653            serde_yaml::from_str("{ name: 42, module: { source: oci://x } }").unwrap();
29654        let err =
29655            upsert_named_entry(&mut arr, entry, FLEET_PROGRAMS_KEY_NAME, || 7u32).unwrap_err();
29656        assert_eq!(err, 7u32);
29657        assert!(arr.is_empty());
29658    }
29659
29660    #[test]
29661    fn upsert_named_entry_uses_parametric_name_key() {
29662        // Name-key-axis-parametric pin: the helper matches on the
29663        // `name_key` parameter, not the pinned
29664        // [`FLEET_PROGRAMS_KEY_NAME`] const — a future writer-side
29665        // upsert path keying on a different discriminator scalar
29666        // (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
29667        // per-entry `spec.selector` axis, an in-progress rebrand
29668        // promoting `id:` alongside `name:`) reaches for the same
29669        // helper with a different key rather than re-inlining the
29670        // upsert loop.
29671        let mut arr: Vec<serde_yaml::Value> =
29672            vec![serde_yaml::from_str("{ id: alpha, payload: original }").unwrap()];
29673        let entry: serde_yaml::Value =
29674            serde_yaml::from_str("{ id: alpha, payload: replaced }").unwrap();
29675        let inserted = upsert_named_entry::<()>(&mut arr, entry, "id", || ()).unwrap();
29676        assert!(!inserted, "matching `id:` must replace, not append");
29677        assert_eq!(arr.len(), 1);
29678        assert_eq!(
29679            arr[0].get("payload").and_then(|p| p.as_str()),
29680            Some("replaced")
29681        );
29682    }
29683
29684    // ── is_dns_1123_label — shared DNS-1123 label predicate ──────────────
29685
29686    #[test]
29687    fn dns_1123_label_accepts_canonical_forms() {
29688        // Substrate-side pin: the predicate accepts the same canonical
29689        // shapes its three caller axes (`:membros :caixa`,
29690        // `:placement :clusters`, `:children :caixa`) accept at their own
29691        // gates. Drift between this list and the per-axis positive-set
29692        // sweeps surfaces here — one source of truth for the rule.
29693        for s in [
29694            "worker",
29695            "a",
29696            "0",
29697            "cache-v2",
29698            "payment-retry",
29699            "2-pool",
29700            "mar-east",
29701        ] {
29702            is_dns_1123_label(s)
29703                .unwrap_or_else(|e| panic!("canonical DNS-1123 label {s:?} must pass: {e:?}"));
29704        }
29705    }
29706
29707    #[test]
29708    fn dns_1123_label_rejects_uppercase_with_lower_suggestion() {
29709        // The diagnostic carries the lower-cased fix verbatim so every
29710        // caller's per-axis `*Invalid { reason }` wrapping the predicate's
29711        // output reads back as a one-edit-fix suggestion. Pinned at the
29712        // substrate layer so the suggestion shape lives in one place.
29713        let err = is_dns_1123_label("Rio").unwrap_err();
29714        assert!(err.contains("uppercase"), "got: {err:?}");
29715        assert!(err.contains("\"rio\""), "got: {err:?}");
29716    }
29717
29718    #[test]
29719    fn dns_1123_label_rejects_at_64_byte_boundary() {
29720        // The 63-byte cap pin — both the boundary-exceeding case and
29721        // the boundary-accepting case in one place, so a future cap
29722        // shift surfaces both arms simultaneously.
29723        let max_ok = "a".repeat(63);
29724        is_dns_1123_label(&max_ok).unwrap();
29725        let too_long = "a".repeat(64);
29726        let err = is_dns_1123_label(&too_long).unwrap_err();
29727        assert!(err.contains("63"), "got: {err:?}");
29728        assert!(err.contains("64"), "got: {err:?}");
29729    }
29730
29731    #[test]
29732    fn dns_1123_label_rejects_empty_defensively() {
29733        // Defensive re-check pin — every peer value-shape predicate in
29734        // this module (`is_gateway_api_http_path`, `is_wit_world_ref`,
29735        // `is_nats_subject`, `is_wasi_keyvalue_slot`, `is_git_ref_name`)
29736        // carries the same empty-first arm, so `is_dns_1123_label("")`
29737        // returns a clean parser-shaped `must not be empty` reason
29738        // instead of panicking at the boundary arm's `bytes[0]` access
29739        // (`bytes[0].is_ascii_alphanumeric()` on an empty slice would
29740        // index out of bounds). The per-axis narrower `*Empty` variant
29741        // (`MembroCaixaEmpty`, `PlacementClusterEmpty`, `EmptyChildName`,
29742        // `ModuleEmpty`) still fires at every current call site — this
29743        // arm exists so any future call site missing the pre-check gets
29744        // a self-locating diagnostic rather than a `panic!` far from the
29745        // source caixa.lisp, matching the "usable from any future call
29746        // site without a shape-mismatch footgun" discipline every peer
29747        // predicate's doc-comment already promises.
29748        let err = is_dns_1123_label("").unwrap_err();
29749        assert!(err.contains("empty"), "got: {err:?}");
29750        assert_eq!(err, "must not be empty");
29751    }
29752
29753    // ── is_gateway_api_http_path — shared HTTP-path predicate ────────────
29754
29755    #[test]
29756    fn gateway_api_http_path_accepts_canonical_forms() {
29757        // Substrate-side pin: the predicate accepts the same canonical
29758        // shapes both caller axes (`:entrada :paths` and `:contratos
29759        // :endpoint`) accept at their own gates. Drift between this
29760        // list and the per-axis positive-set sweeps surfaces here —
29761        // one source of truth for the rule. Includes the bare-root
29762        // `/` (the catch-all both renderers fall back to), the
29763        // `/foo..bar` interior-`..`-substring (not a `..` segment),
29764        // the `/...` and `/foo.` `.`-bearing names (not `.` segments),
29765        // and the percent-encoded form.
29766        for p in [
29767            "/",
29768            "/api/cart",
29769            "/healthz",
29770            "/api/.config",
29771            "/v1/products",
29772            "/products/:id",
29773            "/api/cart/",
29774            "/api/caf%C3%A9",
29775            "/foo..bar",
29776            "/...",
29777            "/charge",
29778        ] {
29779            is_gateway_api_http_path(p)
29780                .unwrap_or_else(|e| panic!("canonical HTTP path {p:?} must pass: {e:?}"));
29781        }
29782    }
29783
29784    #[test]
29785    fn gateway_api_http_path_rejects_each_arm_with_substring_pinned_reason() {
29786        // Substrate-side diagnostic-shape pin: each grammar arm
29787        // surfaces its own distinct reason substring. Pinned here so
29788        // a future reason-wording rephrase that drops any of these
29789        // substrings surfaces at this one place, not piecemeal across
29790        // every per-axis test sweep.
29791        for (path, needle) in [
29792            ("/api?q=1", "must not contain `?`"),
29793            ("/api#frag", "must not contain `#`"),
29794            ("/api my", "whitespace"),
29795            ("/api\x01x", "control character"),
29796            ("/api/café", "non-ASCII"),
29797            ("/api//x", "consecutive `/`"),
29798            ("/api/./x", "`.` segment"),
29799            ("/api/../x", "`..` parent-segment"),
29800        ] {
29801            let err = is_gateway_api_http_path(path)
29802                .err()
29803                .unwrap_or_else(|| panic!("path {path:?} must be rejected"));
29804            assert!(
29805                err.contains(needle),
29806                "path {path:?} reason must contain {needle:?}; got {err:?}"
29807            );
29808        }
29809    }
29810
29811    #[test]
29812    fn gateway_api_http_path_rejects_at_1025_byte_boundary() {
29813        // The 1024-byte cap pin — both the boundary-exceeding case and
29814        // the boundary-accepting case in one place, so a future cap
29815        // shift surfaces both arms simultaneously, mirroring
29816        // `dns_1123_label_rejects_at_64_byte_boundary` on the peer
29817        // predicate.
29818        let max_ok = format!("/{}", "a".repeat(1023));
29819        assert_eq!(max_ok.len(), 1024);
29820        is_gateway_api_http_path(&max_ok).unwrap();
29821        let too_long = format!("/{}", "a".repeat(1024));
29822        assert_eq!(too_long.len(), 1025);
29823        let err = is_gateway_api_http_path(&too_long).unwrap_err();
29824        assert!(err.contains("1024"), "got: {err:?}");
29825        assert!(err.contains("1025"), "got: {err:?}");
29826    }
29827
29828    #[test]
29829    fn gateway_api_http_path_rejects_empty_defensively() {
29830        // The predicate is called only after each caller's narrower
29831        // `*Empty` arm has fired; re-checking here keeps the predicate
29832        // usable from any future call site without an empty-precondition
29833        // footgun, and avoids a panic on `bytes[0]`-style indexing if
29834        // a future arm is added. Same defensive empty-check
29835        // `validate_entrada_path` carries at its call site (55410e4).
29836        let err = is_gateway_api_http_path("").unwrap_err();
29837        assert!(err.contains("empty"), "got: {err:?}");
29838    }
29839
29840    #[test]
29841    fn gateway_api_http_path_rejects_not_absolute_defensively() {
29842        // Defensive re-check of the leading-`/` invariant the per-axis
29843        // call site enforces with its own narrower `*NotAbsolute` arm;
29844        // ensures the predicate is callable from any future call site
29845        // without a shape-mismatch footgun.
29846        let err = is_gateway_api_http_path("api/cart").unwrap_err();
29847        assert!(err.contains('/'), "got: {err:?}");
29848    }
29849
29850    #[test]
29851    fn gateway_api_http_path_rejects_every_reserved_printable_ascii_byte() {
29852        // Substrate-side sweep: every one of the eleven printable-ASCII
29853        // bytes outside the K8s Gateway API HTTPPathMatch.value
29854        // apiserver-side OpenAPI regex
29855        // `^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$`
29856        // accepted set surfaces a self-locating reason naming the
29857        // offending byte verbatim plus the canonical `%XX` percent-
29858        // encoding remediation. RFC 3986 §3.3's `pchar = unreserved /
29859        // pct-encoded / sub-delims / ":" / "@"` grammar excludes these
29860        // bytes from every path segment, so the apiserver rejects them
29861        // at admission time on every
29862        // `HTTPRoute.spec.rules[].matches[].path.value` landing site —
29863        // peer with the `?` / `#` / whitespace / control / non-ASCII
29864        // arms `gateway_api_http_path_rejects_each_arm_with_substring_
29865        // pinned_reason` covers.
29866        //
29867        // Each char surfaces in a path-shape that pins the canonical
29868        // authoring footgun the K8s apiserver would otherwise catch
29869        // far from the caixa.lisp: `{id}` / `[0]` / `<placeholder>`
29870        // template forms, the Windows path-separator typo, the
29871        // shell-regex character footgun, the SQL-string-literal /
29872        // YAML-flow-mapping accidents.
29873        for (path, ch) in [
29874            ("/api/cart\"path", '"'),
29875            ("/api/cart<id>", '<'),
29876            ("/api/cart/<id>", '<'),
29877            ("/api/cart[0]", '['),
29878            ("/api/cart\\path", '\\'),
29879            ("/api/cart]", ']'),
29880            ("/api/cart/^foo", '^'),
29881            ("/api/cart/`foo", '`'),
29882            ("/api/cart/{id}", '{'),
29883            ("/api/cart|alt", '|'),
29884            ("/api/cart}", '}'),
29885        ] {
29886            let err = is_gateway_api_http_path(path)
29887                .err()
29888                .unwrap_or_else(|| panic!("path {path:?} must be rejected"));
29889            assert!(
29890                err.contains("reserved character"),
29891                "path {path:?} reason must name the reserved-character axis; got {err:?}"
29892            );
29893            assert!(
29894                err.contains(&format!("{ch:?}")),
29895                "path {path:?} reason must name the offending byte {ch:?} verbatim; got {err:?}"
29896            );
29897            let hex = format!("%{:02X}", ch as u8);
29898            assert!(
29899                err.contains(&hex),
29900                "path {path:?} reason must surface the canonical {hex:?} percent-encoding \
29901                 remediation; got {err:?}"
29902            );
29903        }
29904    }
29905
29906    #[test]
29907    fn gateway_api_http_path_reserved_char_arm_fires_before_consecutive_slash() {
29908        // Precedence pin: the per-byte loop runs before the post-loop
29909        // structural arms (`//`, `/./`, `/../`), so a path that is
29910        // *both* reserved-char-bearing and consecutive-`/`-bearing
29911        // surfaces the more self-locating reserved-character diagnostic
29912        // first, naming the offending byte verbatim. Mirrors the
29913        // existing `?` / `#` / whitespace / control / non-ASCII arms'
29914        // implicit precedence the
29915        // `gateway_api_http_path_rejects_each_arm_with_substring_
29916        // pinned_reason` pin already establishes for the peer per-byte
29917        // shapes.
29918        let err = is_gateway_api_http_path("/api/{id}//x").unwrap_err();
29919        assert!(
29920            err.contains("reserved character") && err.contains("'{'"),
29921            "got: {err:?}"
29922        );
29923        assert!(
29924            !err.contains("consecutive"),
29925            "the reserved-char arm must fire before the consecutive-`/` arm; got: {err:?}"
29926        );
29927    }
29928
29929    #[test]
29930    fn gateway_api_http_path_accepts_percent_encoded_reserved_chars() {
29931        // Positive-control complement to the reserved-byte rejection
29932        // sweep: every one of the eleven reserved printable-ASCII bytes
29933        // is admissible *when* properly percent-encoded, matching the
29934        // canonical Gateway API HTTPPathMatch.value apiserver-side
29935        // OpenAPI regex's `[%][0-9a-fA-F]{2}` alternative. Pins the
29936        // canonical remediation pathway the reserved-byte arm's reason
29937        // wording names — author who carries a literal `{` percent-
29938        // encodes as `%7B` and the typed slot accepts.
29939        for path in [
29940            "/api/cart%22path",
29941            "/api/cart%3Cid%3E",
29942            "/api/cart%5B0%5D",
29943            "/api/cart%5Cpath",
29944            "/api/cart/%5Efoo",
29945            "/api/cart/%60foo",
29946            "/api/cart/%7Bid%7D",
29947            "/api/cart%7Calt",
29948        ] {
29949            is_gateway_api_http_path(path)
29950                .unwrap_or_else(|e| panic!("percent-encoded path {path:?} must pass: {e:?}"));
29951        }
29952    }
29953
29954    // ── is_wit_world_ref — shared WIT world-reference predicate ──────────
29955
29956    #[test]
29957    fn wit_world_ref_accepts_canonical_forms() {
29958        // Substrate-side pin: the predicate accepts every canonical
29959        // WIT identifier the `:contratos :wit` axis already carries in
29960        // the test fixtures + the example checkout-aplicacao (each
29961        // hand-curated to match real WIT registry references). Drift
29962        // between this list and the per-axis positive-set sweep
29963        // surfaces here — one source of truth for the rule. Includes
29964        // every shape variant: HTTP-prefixed (`wasi:http/proxy`),
29965        // KV-prefixed (`wasi:keyvalue/store`), pubsub-prefixed
29966        // (`nats:pub-sub`, `kafka:topic`), capability-only
29967        // (`custom:exchange`, `pleme:cap/audit`), the optional
29968        // `@<version>` suffix (`wasi:http/proxy@0.2.0`), and the
29969        // multi-segment `/iface/iface` form the WIT IDL grammar allows.
29970        for s in [
29971            "wasi:http/proxy",
29972            "wasi:keyvalue/store",
29973            "nats:pub-sub",
29974            "kafka:topic",
29975            "custom:exchange",
29976            "pleme:cap/audit",
29977            "http:server",
29978            "kv:store",
29979            "wasi:http/proxy@0.2.0",
29980            "wasi:keyvalue/store@0.2.0-rc.1",
29981            "pleme:cap/audit/v2",
29982            // Every legal shape SemVer 2.0.0 admits in the `@<version>`
29983            // body — bare numeric core, pre-release suffix (single +
29984            // dot-separated identifiers), build-metadata suffix (single
29985            // + dot-separated identifiers), combined pre-release +
29986            // build-metadata, and leading-zero-avoiding pre-release
29987            // identifiers — pinned here so a future tightening of the
29988            // per-byte accepted set that rejects a canonical semver
29989            // shape surfaces here rather than at the M4 CR materializer's
29990            // WIT-parse boundary.
29991            "wasi:http/proxy@1.0.0",
29992            "wasi:http/proxy@0.2.0-alpha",
29993            "wasi:http/proxy@1.0.0-alpha.1",
29994            "wasi:http/proxy@2.0.0+build.42",
29995            "wasi:http/proxy@0.0.0-rc.1+abc.def",
29996        ] {
29997            is_wit_world_ref(s)
29998                .unwrap_or_else(|e| panic!("canonical WIT reference {s:?} must pass: {e:?}"));
29999        }
30000    }
30001
30002    #[test]
30003    fn wit_world_ref_rejects_each_arm_with_substring_pinned_reason() {
30004        // Substrate-side diagnostic-shape pin: each grammar arm
30005        // surfaces its own distinct reason substring. Pinned here so a
30006        // future reason-wording rephrase that drops any of these
30007        // substrings surfaces at this one place, not piecemeal across
30008        // every per-axis test sweep. Mirrors
30009        // `gateway_api_http_path_rejects_each_arm_with_substring_pinned_reason`
30010        // on the peer predicate.
30011        for (s, needle) in [
30012            // Missing `:` separator → silent capability demotion.
30013            ("wasi-http/proxy", "must contain a `:`"),
30014            // Multiple `:` → can't split into ns + pkg.
30015            ("wasi:http:proxy", "exactly one `:`"),
30016            // Uppercase → silently bypasses the lowercase dispatch.
30017            ("WASI:http/proxy", "lowercase"),
30018            ("wasi:HTTP/proxy", "lowercase"),
30019            // Empty package half → can't resolve via WIT registry.
30020            ("wasi:", "must not be empty"),
30021            // Empty namespace half.
30022            (":http/proxy", "must not be empty"),
30023            // Underscore → DNS-1123 / WIT kebab-case footgun.
30024            ("wasi:http_proxy", "_"),
30025            // Leading digit → WIT identifiers begin with a letter.
30026            ("wasi:1http/proxy", "digit"),
30027            // Consecutive hyphens → invalid kebab-case.
30028            ("wasi:pub--sub", "consecutive `-`"),
30029            // Trailing hyphen → invalid kebab-case.
30030            ("wasi:proxy-", "must not end with `-`"),
30031            // Whitespace inside the token.
30032            ("wasi:http proxy", "whitespace"),
30033            // Control characters.
30034            ("wasi:http\x01proxy", "control character"),
30035            // Non-ASCII byte (café-style un-percent-encoded literal).
30036            ("wasi:caf\u{e9}/proxy", "non-ASCII"),
30037            // Trailing `@` with no version body.
30038            ("wasi:http/proxy@", "trailing `@`"),
30039            // Version body carrying `:` or `/`.
30040            ("wasi:http/proxy@0.2:rc1", "must not contain `:` or `/`"),
30041            // Doubled `@`.
30042            ("wasi:http/proxy@0.2@beta", "at most one `@`"),
30043            // Version body carrying a byte outside the SemVer 2.0.0
30044            // accepted set `[0-9A-Za-z.\-+]` — the canonical
30045            // author-side paste footguns (`?` from URL-query-separator
30046            // paste, `#` from URL-fragment paste, `!` from
30047            // history-expansion, `(` from parenthetical doc annotation,
30048            // `~` from tilde-range npm/Cargo semver-req paste that
30049            // strayed into the version body itself). Each surfaces the
30050            // `invalid character` reason substring so the diagnostic
30051            // wording is pinned alongside every peer per-byte rejection.
30052            ("wasi:http/proxy@0.2.0?rc1", "invalid character"),
30053            ("wasi:http/proxy@0.2.0#build", "invalid character"),
30054            ("wasi:http/proxy@0.2.0!alpha", "invalid character"),
30055            ("wasi:http/proxy@0.2.0(rc1)", "invalid character"),
30056            ("wasi:http/proxy@~0.2.0", "invalid character"),
30057            // Version body byte-set-valid but *structurally* invalid
30058            // SemVer 2.0.0 — the canonical author-side paste footguns
30059            // the byte-set gate above cannot catch. Every entry passes
30060            // the accepted-set arm `[0-9A-Za-z.\-+]` verbatim and
30061            // fails only at [`semver::Version::parse`]: two-part
30062            // numeric core (`@1.0` — Node.js `"engines"` field paste),
30063            // one-part numeric core (`@1` — Docker `:v1` tag paste),
30064            // four-part numeric core (`@1.0.0.0` — Microsoft / Java
30065            // build-number convention), `v`-prefixed version body
30066            // (`@v0.2.0` — git-tag-shape paste), leading-zero major
30067            // (`@01.0.0` — mistaken zero-padded date-based version),
30068            // trailing hyphen with empty pre-release (`@1.0.0-` —
30069            // half-typed pre-release), trailing plus with empty
30070            // build-metadata (`@1.0.0+` — peer for build-metadata),
30071            // empty pre-release identifier between dots
30072            // (`@1.0.0-.rc1` — accidental leading `.`), empty build-
30073            // metadata identifier between dots (`@1.0.0+.abc` — peer
30074            // for build-metadata), numeric pre-release identifier
30075            // with leading zero (`@1.0.0-01` — SemVer 2.0.0 rule 9),
30076            // consecutive dots inside pre-release (`@1.0.0-alpha..beta`).
30077            // Each surfaces the `structurally valid SemVer 2.0.0`
30078            // reason substring so the diagnostic wording is pinned
30079            // alongside every peer structural rejection.
30080            ("wasi:http/proxy@1.0", "structurally valid SemVer 2.0.0"),
30081            ("wasi:http/proxy@1", "structurally valid SemVer 2.0.0"),
30082            ("wasi:http/proxy@1.0.0.0", "structurally valid SemVer 2.0.0"),
30083            ("wasi:http/proxy@v0.2.0", "structurally valid SemVer 2.0.0"),
30084            ("wasi:http/proxy@01.0.0", "structurally valid SemVer 2.0.0"),
30085            ("wasi:http/proxy@1.0.0-", "structurally valid SemVer 2.0.0"),
30086            ("wasi:http/proxy@1.0.0+", "structurally valid SemVer 2.0.0"),
30087            (
30088                "wasi:http/proxy@1.0.0-.rc1",
30089                "structurally valid SemVer 2.0.0",
30090            ),
30091            (
30092                "wasi:http/proxy@1.0.0+.abc",
30093                "structurally valid SemVer 2.0.0",
30094            ),
30095            (
30096                "wasi:http/proxy@1.0.0-01",
30097                "structurally valid SemVer 2.0.0",
30098            ),
30099            (
30100                "wasi:http/proxy@1.0.0-alpha..beta",
30101                "structurally valid SemVer 2.0.0",
30102            ),
30103            // Digit-immediately-after-`-` word-start rule — the WIT IDL
30104            // `word ::= [a-z][a-z0-9]*` per-word first-byte gate the
30105            // predicate's doc-comment already documented, closed at the
30106            // implementation layer. Each identifier passes the outer
30107            // `[a-z0-9-]` byte set, the leading-`-` rejection, the
30108            // consecutive-`-` rejection, and the trailing-`-` rejection,
30109            // and was silently accepted before the arm landed — surfaces
30110            // the `word after `-`` reason substring so a future
30111            // diagnostic-wording rephrase surfaces here alongside every
30112            // peer per-arm substring pin. Canonical author-side
30113            // footguns: `"pub-1sub"` (version-shape digit paste),
30114            // `"proxy-2beta"` (v2 tag paste), `"cap-9"` (numeric
30115            // suffix). Namespace-side and interface-side variants pin
30116            // the arm fires uniformly on every WIT segment (`ns:pkg`,
30117            // `ns:pkg/iface`, not just the first).
30118            ("wasi:pub-1sub", "word after `-`"),
30119            ("wasi:proxy-2beta", "word after `-`"),
30120            ("wasi:cap-9", "word after `-`"),
30121            ("pleme-1cap:audit", "word after `-`"),
30122            ("wasi:http/proxy-3rc", "word after `-`"),
30123        ] {
30124            let err = is_wit_world_ref(s)
30125                .err()
30126                .unwrap_or_else(|| panic!("WIT reference {s:?} must be rejected"));
30127            assert!(
30128                err.contains(needle),
30129                "WIT reference {s:?} reason must contain {needle:?}; got {err:?}"
30130            );
30131        }
30132    }
30133
30134    #[test]
30135    fn wit_world_ref_word_after_hyphen_digit_arm_names_offending_byte_and_word_rule() {
30136        // Pin the per-word first-byte arm's diagnostic quality: the
30137        // offending byte appears verbatim in the reason, the WIT
30138        // grammar production is named (`[a-z][a-z0-9]*`), and the
30139        // remediation suggests a lowercase-letter prefix on the
30140        // offending word. Mirrors the `wit_world_ref_leading_digit`
30141        // sibling pin on the *first-word* first-byte arm — the two
30142        // arms enforce the same rule at complementary positions
30143        // (whole-id first byte vs. per-hyphen-word first byte), so
30144        // their diagnostic shapes stay peer.
30145        let err = is_wit_world_ref("wasi:pub-1sub").unwrap_err();
30146        assert!(err.contains("'1'"), "must name offending byte: {err:?}");
30147        assert!(
30148            err.contains("[a-z][a-z0-9]*"),
30149            "must name WIT word grammar: {err:?}"
30150        );
30151        assert!(
30152            err.contains("pub-v1sub"),
30153            "must suggest the letter-prefix remediation: {err:?}"
30154        );
30155    }
30156
30157    #[test]
30158    fn wit_world_ref_word_after_hyphen_lowercase_letter_still_accepted() {
30159        // Complement-side pin: the per-word first-byte arm strictly
30160        // targets *digits* after `-`; every canonical multi-word
30161        // lowercase identifier (`pub-sub`, `pub-sub-async`,
30162        // `wasi:http/incoming-handler`, `wasi:keyvalue/atomic-batch`)
30163        // remains in the accepted set with no new false-positive.
30164        // Pinned here so a future tightening that spills the digit-
30165        // rejection arm onto the letter-after-hyphen class surfaces
30166        // as a test failure at this positive-set pin, not at the M4
30167        // CR materializer's WIT-parse boundary. Mirrors the
30168        // `wit_world_ref_accepts_canonical_forms` positive-set
30169        // sweep, extended here to the multi-word-lowercase axis.
30170        for s in [
30171            "nats:pub-sub",
30172            "wasi:http/incoming-handler",
30173            "wasi:keyvalue/atomic-batch",
30174            "pleme:cap/audit-log",
30175            "http:server-side",
30176        ] {
30177            is_wit_world_ref(s).unwrap_or_else(|e| {
30178                panic!("canonical multi-word WIT identifier {s:?} must pass: {e:?}")
30179            });
30180        }
30181    }
30182
30183    #[test]
30184    fn wit_world_ref_word_after_hyphen_digit_arm_fires_before_byte_set_arm() {
30185        // Diagnostic-precedence pin: an identifier that is *both*
30186        // digit-after-`-` and byte-set-invalid (`"pub-1$"`) surfaces
30187        // the more self-locating word-start diagnostic, not the
30188        // generic invalid-character diagnostic. The arm order in the
30189        // loop is deliberate — the per-word first-byte gate fires on
30190        // the first offending byte (position 4 = the `1`) before the
30191        // byte-set gate can reach the `$` at position 5. Pinned here
30192        // so a future arm-reordering that moves the byte-set gate
30193        // earlier surfaces the drift at this test rather than
30194        // silently value-laundering the diagnostic.
30195        let err = is_wit_world_ref("wasi:pub-1$").unwrap_err();
30196        assert!(
30197            err.contains("word after `-`"),
30198            "must surface the per-word first-byte diagnostic, not the invalid-character one: {err:?}"
30199        );
30200        // And the `$` case *without* the digit-after-`-` still lands
30201        // on the invalid-character arm — the two diagnostics don't
30202        // collide when only one applies.
30203        let err = is_wit_world_ref("wasi:pub-x$").unwrap_err();
30204        assert!(
30205            err.contains("invalid character"),
30206            "byte-set-only rejection must still name invalid character: {err:?}"
30207        );
30208    }
30209
30210    #[test]
30211    fn wit_world_ref_rejects_empty_defensively() {
30212        // The predicate is called from `WitContract::target()` only
30213        // after the per-axis `EmptyWit` arm has fired at validate
30214        // time; re-checking here keeps the predicate usable from any
30215        // future call site without an empty-precondition footgun.
30216        // Same defensive empty-check `is_dns_1123_label` /
30217        // `is_gateway_api_http_path` carry at their call sites.
30218        let err = is_wit_world_ref("").unwrap_err();
30219        assert!(err.contains("empty"), "got: {err:?}");
30220    }
30221
30222    #[test]
30223    fn wit_world_ref_rejects_at_129_byte_boundary() {
30224        // The 128-byte cap pin — both the boundary-exceeding case and
30225        // the boundary-accepting case in one place, so a future cap
30226        // shift surfaces both arms simultaneously, mirroring
30227        // `dns_1123_label_rejects_at_64_byte_boundary` and
30228        // `gateway_api_http_path_rejects_at_1025_byte_boundary` on the
30229        // peer predicates. Constructed as `wasi:<long-pkg>` so the
30230        // kebab-shape arms don't fire first and obscure the cap arm.
30231        let pad = "a".repeat(123); // 5 + 123 = 128 (`wasi:` + pad)
30232        let max_ok = format!("wasi:{pad}");
30233        assert_eq!(max_ok.len(), 128);
30234        is_wit_world_ref(&max_ok).unwrap();
30235        let pad_over = "a".repeat(124);
30236        let too_long = format!("wasi:{pad_over}");
30237        assert_eq!(too_long.len(), 129);
30238        let err = is_wit_world_ref(&too_long).unwrap_err();
30239        assert!(err.contains("128"), "got: {err:?}");
30240        assert!(err.contains("129"), "got: {err:?}");
30241    }
30242
30243    // ── is_nats_subject — shared NATS subject predicate ──────────────────
30244
30245    #[test]
30246    fn nats_subject_accepts_canonical_forms() {
30247        // Substrate-side pin: the predicate accepts every canonical
30248        // NATS subject the `:contratos :subject` axis carries in the
30249        // caixa-mesh test fixtures + the example checkout-aplicacao
30250        // (each hand-curated to match real NATS server-side admission
30251        // shapes). Drift between this list and the per-axis positive-
30252        // set sweep surfaces here — one source of truth for the rule.
30253        // Includes single-token subjects, multi-dot subjects, snake-
30254        // case + kebab-case tokens (NATS accepts both), digit-bearing
30255        // tokens, the `*` single-token wildcard at every segment
30256        // position, and the `>` multi-token wildcard at the final
30257        // position (the two NATS subscription patterns the protocol
30258        // defines). Mirrors the canonical-forms sweeps on the peer
30259        // value-shape predicates (`gateway_api_http_path_accepts_…`,
30260        // `wit_world_ref_accepts_…`).
30261        for s in [
30262            "checkout.events.charge.failed",
30263            "rio.events.order.charged",
30264            "orders",
30265            "orders.123",
30266            "snake_case.token",
30267            "kebab-case.token",
30268            "MixedCase.Token",
30269            "alpha.beta.gamma.delta.epsilon",
30270            "orders.*.charged",
30271            "*.events.*",
30272            "orders.>",
30273            "*",
30274            ">",
30275        ] {
30276            is_nats_subject(s)
30277                .unwrap_or_else(|e| panic!("canonical NATS subject {s:?} must pass: {e:?}"));
30278        }
30279    }
30280
30281    #[test]
30282    fn nats_subject_rejects_each_arm_with_substring_pinned_reason() {
30283        // Substrate-side diagnostic-shape pin: each grammar arm
30284        // surfaces its own distinct reason substring. Pinned here so
30285        // a future reason-wording rephrase that drops any of these
30286        // substrings surfaces at this one place, not piecemeal across
30287        // every per-axis test sweep. Mirrors
30288        // `gateway_api_http_path_rejects_each_arm_with_substring_pinned_reason`
30289        // and `wit_world_ref_rejects_each_arm_with_substring_pinned_reason`
30290        // on the peer predicates.
30291        for (s, needle) in [
30292            // Whitespace inside the token.
30293            ("foo bar", "whitespace"),
30294            ("foo\tbar", "whitespace"),
30295            // Control characters.
30296            ("foo\x01bar", "control character"),
30297            // Non-ASCII byte (un-percent-encoded café-style literal).
30298            ("foo.caf\u{e9}", "non-ASCII"),
30299            // Leading `.` — empty leading token.
30300            (".foo", "must not start with `.`"),
30301            // Trailing `.` — empty trailing token.
30302            ("foo.", "must not end with `.`"),
30303            // Consecutive `.` — empty token between separators.
30304            ("foo..bar", "consecutive `.`"),
30305            // Non-trailing `>` multi-token wildcard.
30306            ("foo.>.bar", "only allowed as the final segment"),
30307            // Mid-segment `*` (not a standalone wildcard token).
30308            ("foo*.bar", "`*` mid-segment"),
30309            // Mid-segment `>` (not a standalone wildcard token).
30310            ("foo>", "`>` mid-segment"),
30311            // `.` is the separator, so `,` (or any other punctuation)
30312            // surfaces as an invalid-character arm.
30313            ("foo,bar", "invalid character"),
30314            // `:` reserved-looking — distinct invalid-character arm
30315            // (pinned separately so a future relaxation that accepts
30316            // `:` mid-segment surfaces here, not in some downstream
30317            // renderer's "this passed validate but the NATS server
30318            // rejected at publish" footgun).
30319            ("foo:bar", "invalid character"),
30320        ] {
30321            let err = is_nats_subject(s)
30322                .err()
30323                .unwrap_or_else(|| panic!("NATS subject {s:?} must be rejected"));
30324            assert!(
30325                err.contains(needle),
30326                "NATS subject {s:?} reason must contain {needle:?}; got {err:?}"
30327            );
30328        }
30329    }
30330
30331    #[test]
30332    fn nats_subject_rejects_empty_defensively() {
30333        // The predicate is called from `WitContract::target()` only
30334        // after the per-axis `ContratoSubjectEmpty` arm has fired at
30335        // validate time; re-checking here keeps the predicate usable
30336        // from any future call site without an empty-precondition
30337        // footgun. Same defensive empty-check `is_dns_1123_label`,
30338        // `is_gateway_api_http_path`, and `is_wit_world_ref` carry at
30339        // their call sites.
30340        let err = is_nats_subject("").unwrap_err();
30341        assert!(err.contains("empty"), "got: {err:?}");
30342    }
30343
30344    #[test]
30345    fn nats_subject_rejects_at_257_byte_boundary() {
30346        // The 256-byte cap pin — both the boundary-exceeding case and
30347        // the boundary-accepting case in one place, so a future cap
30348        // shift surfaces both arms simultaneously, mirroring
30349        // `dns_1123_label_rejects_at_64_byte_boundary`,
30350        // `gateway_api_http_path_rejects_at_1025_byte_boundary`, and
30351        // `wit_world_ref_rejects_at_129_byte_boundary` on the peer
30352        // predicates. Constructed as a single all-`a` token (no `.`)
30353        // so the segment / wildcard arms don't fire first and obscure
30354        // the cap arm.
30355        let max_ok = "a".repeat(256);
30356        assert_eq!(max_ok.len(), 256);
30357        is_nats_subject(&max_ok).unwrap();
30358        let too_long = "a".repeat(257);
30359        assert_eq!(too_long.len(), 257);
30360        let err = is_nats_subject(&too_long).unwrap_err();
30361        assert!(err.contains("256"), "got: {err:?}");
30362        assert!(err.contains("257"), "got: {err:?}");
30363    }
30364
30365    #[test]
30366    fn nats_subject_lone_wildcard_tokens_validate() {
30367        // The two NATS wildcards stand alone as the entire subject —
30368        // a `subscribe("*")` matches any single-token publish, a
30369        // `subscribe(">")` matches every NATS message on the connection.
30370        // Both are protocol-legal; the typed substrate accepts them
30371        // structurally and leaves the "should the typed `:contratos`
30372        // edge subscribe to literally everything?" question to a
30373        // future semantic-level gate. Pinned alongside the canonical-
30374        // forms sweep so a future tighten that disallows lone wildcards
30375        // surfaces both arms simultaneously.
30376        is_nats_subject("*").unwrap();
30377        is_nats_subject(">").unwrap();
30378    }
30379
30380    #[test]
30381    fn nats_subject_trailing_multi_wildcard_validates() {
30382        // `>` at the final segment is the canonical "match all trailing
30383        // tokens" subscription pattern. Pinned alongside the non-
30384        // trailing-`>` rejection arm so the boundary between the two
30385        // is in one place — a future relaxation that allows `>` at
30386        // non-trailing positions or a tighten that disallows trailing
30387        // `>` surfaces both arms simultaneously.
30388        is_nats_subject("orders.>").unwrap();
30389        is_nats_subject("orders.events.>").unwrap();
30390        // And the `*` single-token wildcard combines freely with the
30391        // trailing `>` — the canonical "match one middle token, then
30392        // anything trailing" subscription pattern.
30393        is_nats_subject("orders.*.>").unwrap();
30394    }
30395
30396    // ── is_wasi_keyvalue_slot — shared kv slot-template predicate ────────
30397
30398    #[test]
30399    fn wasi_kv_slot_accepts_canonical_forms() {
30400        // Substrate-side pin: the predicate accepts every canonical kv
30401        // slot template the `:contratos :slot` axis carries in the
30402        // caixa-mesh test fixtures + plausible authoring patterns
30403        // (each maps to a realistic wasi:keyvalue/store key the runtime
30404        // resolves on dispatch). Drift between this list and the
30405        // per-axis positive-set sweep surfaces here — one source of
30406        // truth for the rule. Includes:
30407        //   - single-token identifiers (`"checkout"`, `"events"`);
30408        //   - dot-namespaced templates (`"session.tokens.<sid>"`);
30409        //   - path-namespaced templates with `$`-prefixed variables
30410        //     (`"checkout/$orderId"`, the canonical Akka-cluster-
30411        //     sharding-style template);
30412        //   - colon-namespaced templates with brace placeholders
30413        //     (`"users:{tenant}/{id}"`, the canonical multi-tenant
30414        //     Redis-key shape);
30415        //   - angle-bracket placeholders (`"session.<sid>"`);
30416        //   - underscore identifiers (`"snake_case_key"`);
30417        //   - kebab identifiers (`"kebab-case-key"`);
30418        //   - mixed-case (`"MixedCase"` — kv slot templates are case-
30419        //     sensitive; the predicate doesn't lowercase-fold);
30420        //   - digit-bearing tokens (`"shard0"`, `"v2/key"`);
30421        //   - percent-encoded fragments (`"users/caf%C3%A9"`); the
30422        //     encoded form is the *valid* shape, the raw `café` is
30423        //     rejected on the non-ASCII arm.
30424        // Mirrors the canonical-forms sweeps on the peer value-shape
30425        // predicates (`gateway_api_http_path_accepts_…`,
30426        // `nats_subject_accepts_canonical_forms`).
30427        for s in [
30428            "checkout",
30429            "events",
30430            "checkout/$orderId",
30431            "users:{tenant}/{id}",
30432            "session.<sid>",
30433            "session.tokens.<sid>",
30434            "snake_case_key",
30435            "kebab-case-key",
30436            "MixedCase",
30437            "shard0",
30438            "v2/key",
30439            "users/caf%C3%A9",
30440        ] {
30441            is_wasi_keyvalue_slot(s)
30442                .unwrap_or_else(|e| panic!("canonical kv slot {s:?} must pass: {e:?}"));
30443        }
30444    }
30445
30446    #[test]
30447    fn wasi_kv_slot_rejects_each_arm_with_substring_pinned_reason() {
30448        // Substrate-side diagnostic-shape pin: each grammar arm
30449        // surfaces its own distinct reason substring. Pinned here so
30450        // a future reason-wording rephrase that drops any of these
30451        // substrings surfaces at this one place, not piecemeal across
30452        // every per-axis test sweep. Mirrors
30453        // `nats_subject_rejects_each_arm_with_substring_pinned_reason`
30454        // and `gateway_api_http_path_rejects_each_arm_with_substring_pinned_reason`
30455        // on the peer predicates.
30456        for (s, needle) in [
30457            // Raw space inside the template — the canonical paste-from-
30458            // doc footgun.
30459            ("check out/$order", "whitespace"),
30460            // Tab byte — distinct arm-pinned reason from the space arm.
30461            ("check\tout", "whitespace"),
30462            // Control character (SOH = 0x01) — pinned separately from
30463            // the whitespace arm so a future relaxation that admits
30464            // raw whitespace but still rejects controls surfaces here.
30465            ("checkout/\x01order", "control character"),
30466            // Newline — the canonical "the paste-from-binary slug
30467            // spans multiple lines" footgun. Distinct from the
30468            // whitespace arm because `\n` is a control character.
30469            ("checkout\norder", "control character"),
30470            // DEL byte (0x7F) — the upper boundary of the control-
30471            // character range, pinned so a future relaxation that
30472            // only checks `< 0x20` surfaces here.
30473            ("checkout\x7forder", "control character"),
30474            // Un-percent-encoded non-ASCII byte — the canonical
30475            // "I copied the key from a doc with smart quotes /
30476            // accented characters" footgun. Author must percent-
30477            // encode (the canonical-forms sweep covers
30478            // `"users/caf%C3%A9"`).
30479            ("ch\u{e9}ckout/$order", "non-ASCII"),
30480        ] {
30481            let err = is_wasi_keyvalue_slot(s)
30482                .err()
30483                .unwrap_or_else(|| panic!("kv slot {s:?} must be rejected"));
30484            assert!(
30485                err.contains(needle),
30486                "kv slot {s:?} reason must contain {needle:?}; got {err:?}"
30487            );
30488        }
30489    }
30490
30491    #[test]
30492    fn wasi_kv_slot_rejects_empty_defensively() {
30493        // The predicate is called from `WitContract::target()` only
30494        // after the per-axis `ContratoSlotEmpty` arm has fired at
30495        // validate time; re-checking here keeps the predicate usable
30496        // from any future call site without an empty-precondition
30497        // footgun. Same defensive empty-check `is_dns_1123_label`,
30498        // `is_gateway_api_http_path`, `is_wit_world_ref`, and
30499        // `is_nats_subject` carry at their call sites.
30500        let err = is_wasi_keyvalue_slot("").unwrap_err();
30501        assert!(err.contains("empty"), "got: {err:?}");
30502    }
30503
30504    #[test]
30505    fn wasi_kv_slot_rejects_at_513_byte_boundary() {
30506        // The 512-byte cap pin — both the boundary-exceeding case and
30507        // the boundary-accepting case in one place, so a future cap
30508        // shift surfaces both arms simultaneously, mirroring
30509        // `dns_1123_label_rejects_at_64_byte_boundary`,
30510        // `gateway_api_http_path_rejects_at_1025_byte_boundary`,
30511        // `wit_world_ref_rejects_at_129_byte_boundary`, and
30512        // `nats_subject_rejects_at_257_byte_boundary` on the peer
30513        // predicates. Constructed as a single all-`a` token (no
30514        // separator / template syntax) so only the cap arm fires.
30515        let max_ok = "a".repeat(512);
30516        assert_eq!(max_ok.len(), 512);
30517        is_wasi_keyvalue_slot(&max_ok).unwrap();
30518        let too_long = "a".repeat(513);
30519        assert_eq!(too_long.len(), 513);
30520        let err = is_wasi_keyvalue_slot(&too_long).unwrap_err();
30521        assert!(err.contains("512"), "got: {err:?}");
30522        assert!(err.contains("513"), "got: {err:?}");
30523    }
30524
30525    #[test]
30526    fn wasi_kv_slot_admits_full_printable_ascii_range() {
30527        // Structural pin: the predicate admits every printable ASCII
30528        // byte from `0x21` (`!`) to `0x7E` (`~`) inclusive, including
30529        // every template-variable bracket the documented authoring
30530        // patterns use (`$`, `{`, `}`, `<`, `>`) and every namespace
30531        // separator (`/`, `:`, `.`, `-`, `_`). Drift here = a future
30532        // tighten that removes any byte from the admitted set surfaces
30533        // a name-the-byte test failure, not piecemeal across per-axis
30534        // sweeps. Constructed as a single all-bytes template (`b!`,
30535        // `b"`, …, `b~`) — the predicate doesn't impose structure,
30536        // only character-class.
30537        for b in 0x21u8..=0x7E {
30538            let s = std::str::from_utf8(&[b]).unwrap().to_string();
30539            is_wasi_keyvalue_slot(&s)
30540                .unwrap_or_else(|e| panic!("printable ASCII byte 0x{b:02x} must pass: {e:?}"));
30541        }
30542    }
30543
30544    #[test]
30545    fn git_ref_name_accepts_canonical_forms() {
30546        // Substrate-side pin: the predicate accepts every canonical
30547        // refname the `:fonte :tag` / `:fonte :branch` axes carry in
30548        // realistic authoring patterns (each maps to a refname `git
30549        // fetch <remote> tag '<value>'` and `git checkout '<value>'`
30550        // resolve cleanly at clone time). Drift between this list and
30551        // any per-axis positive-set sweep surfaces here — one source
30552        // of truth for the rule. Includes:
30553        //   - semver tag with `v` prefix (`"v0.1.0"`, the canonical
30554        //     pleme-io release shape);
30555        //   - bare semver tag (`"0.1.0"`, the npm / Cargo idiom);
30556        //   - pre-release tag (`"v0.1.0-alpha.1"`);
30557        //   - release-line tag with hyphens (`"release-1.0"`);
30558        //   - leaf branch (`"main"` / `"master"`);
30559        //   - hierarchical feature branch (`"feature/checkout"`);
30560        //   - multi-component branch with hyphens and digits
30561        //     (`"user-1/feat-x-v2"`);
30562        //   - dot-bearing tag (`"v0.1.0.rc1"`, mid-component dot
30563        //     allowed — only consecutive `..` and trailing `.` are
30564        //     rejected).
30565        // Mirrors the canonical-forms sweeps on the peer value-shape
30566        // predicates (`wasi_kv_slot_accepts_canonical_forms`,
30567        // `nats_subject_accepts_canonical_forms`).
30568        for s in [
30569            "v0.1.0",
30570            "0.1.0",
30571            "v0.1.0-alpha.1",
30572            "release-1.0",
30573            "main",
30574            "master",
30575            "feature/checkout",
30576            "user-1/feat-x-v2",
30577            "v0.1.0.rc1",
30578            "stable",
30579        ] {
30580            is_git_ref_name(s)
30581                .unwrap_or_else(|e| panic!("canonical git ref {s:?} must pass: {e:?}"));
30582        }
30583    }
30584
30585    #[test]
30586    fn git_ref_name_rejects_each_arm_with_substring_pinned_reason() {
30587        // Substrate-side diagnostic-shape pin: each grammar arm
30588        // surfaces its own distinct reason substring. Pinned here so
30589        // a future reason-wording rephrase that drops any of these
30590        // substrings surfaces at this one place, not piecemeal across
30591        // every per-axis test sweep. Mirrors
30592        // `wasi_kv_slot_rejects_each_arm_with_substring_pinned_reason`
30593        // and `nats_subject_rejects_each_arm_with_substring_pinned_reason`
30594        // on the peer predicates.
30595        for (s, needle) in [
30596            // Trailing space — the canonical paste-from-doc footgun.
30597            ("v0.1.0 ", "whitespace"),
30598            // Embedded space (branch with spaces).
30599            ("feature/foo bar", "whitespace"),
30600            // Tab byte.
30601            ("v0.1.0\t", "whitespace"),
30602            // Newline — the canonical "paste-from-multiline-doc"
30603            // footgun. Distinct from the whitespace arm because `\n`
30604            // is a control character.
30605            ("v0.1.0\n", "control character"),
30606            // DEL byte (0x7F) — upper boundary of the control range.
30607            ("v0.1.0\x7f", "control character"),
30608            // Non-ASCII byte (the canonical "I copied the tag from a
30609            // doc with smart quotes" footgun).
30610            ("v0.1.0\u{e9}", "non-ASCII"),
30611            // Tilde — git's revision grammar (`HEAD~3`).
30612            ("v0.1.0~1", "`~`"),
30613            // Caret — git's revision grammar (`HEAD^`).
30614            ("v0.1.0^", "`^`"),
30615            // Colon — git's refspec separator.
30616            ("v0.1.0:rebase", "`:`"),
30617            // Question mark — git's refspec glob.
30618            ("v0.1.0?", "`?`"),
30619            // Asterisk — git's refspec glob.
30620            ("v0.1.*", "`*`"),
30621            // Open bracket — git's refspec glob.
30622            ("v0.1.0[1]", "`[`"),
30623            // Backslash — the canonical Windows-path-leak footgun.
30624            ("feature\\foo", "`\\`"),
30625            // Consecutive dots — git's `<rev1>..<rev2>` range grammar.
30626            ("v0.1..0", "`..`"),
30627            // Reflog grammar.
30628            ("main@{upstream}", "`@{`"),
30629            // The bare `@` — git aliases to `HEAD`.
30630            ("@", "bare `@`"),
30631            // Leading slash.
30632            ("/main", "begin with `/`"),
30633            // Trailing slash.
30634            ("feature/", "end with `/`"),
30635            // Consecutive slashes.
30636            ("feature//foo", "consecutive `/`"),
30637            // Trailing dot.
30638            ("v0.1.0.", "end with `.`"),
30639            // Fully-qualified branch ref — the canonical
30640            // `git show-ref`-output-leak footgun.
30641            ("refs/heads/main", "fully-qualified"),
30642            // Fully-qualified tag ref.
30643            ("refs/tags/v0.1.0", "fully-qualified"),
30644            // Component beginning with `.` (per-component rule).
30645            ("feature/.hidden", "begin with `.`"),
30646            // Component ending with `.lock` (per-component rule).
30647            ("feature/main.lock", "`.lock`"),
30648            // Leaf ref named `<x>.lock` — same per-component rule on
30649            // the single-component refname.
30650            ("main.lock", "`.lock`"),
30651            // Case-insensitive `.LOCK` — APFS / NTFS / HFS+ admit
30652            // both spellings as the same on-disk file, so a
30653            // `:tag "v1.LOCK"` collides with git's atomic-rename
30654            // guard on case-insensitive filesystems. Pinned
30655            // separately from the canonical lowercase arm so a
30656            // future relaxation that only catches lowercase
30657            // surfaces here.
30658            ("v1.LOCK", "`.lock`"),
30659            ("feature/Main.Lock", "`.lock`"),
30660        ] {
30661            let err = is_git_ref_name(s)
30662                .err()
30663                .unwrap_or_else(|| panic!("git ref {s:?} must be rejected"));
30664            assert!(
30665                err.contains(needle),
30666                "git ref {s:?} reason must contain {needle:?}; got {err:?}"
30667            );
30668        }
30669    }
30670
30671    #[test]
30672    fn git_ref_name_rejects_empty_defensively() {
30673        // The predicate is called from `DepSource::validate` only
30674        // after the per-axis `FontePinEmpty` arm has fired at
30675        // validate time; re-checking here keeps the predicate usable
30676        // from any future call site without an empty-precondition
30677        // footgun. Same defensive empty-check `is_dns_1123_label`,
30678        // `is_gateway_api_http_path`, `is_wit_world_ref`,
30679        // `is_nats_subject`, and `is_wasi_keyvalue_slot` carry at
30680        // their call sites.
30681        let err = is_git_ref_name("").unwrap_err();
30682        assert!(err.contains("empty"), "got: {err:?}");
30683    }
30684
30685    #[test]
30686    fn git_ref_name_rejects_at_256_byte_boundary() {
30687        // The 255-byte cap pin — both the boundary-exceeding case and
30688        // the boundary-accepting case in one place, so a future cap
30689        // shift surfaces both arms simultaneously, mirroring
30690        // `dns_1123_label_rejects_at_64_byte_boundary`,
30691        // `gateway_api_http_path_rejects_at_1025_byte_boundary`,
30692        // `wit_world_ref_rejects_at_129_byte_boundary`,
30693        // `nats_subject_rejects_at_257_byte_boundary`, and
30694        // `wasi_kv_slot_rejects_at_513_byte_boundary` on the peer
30695        // predicates. Constructed as a single all-`a` leaf so only
30696        // the cap arm fires.
30697        let max_ok = "a".repeat(255);
30698        assert_eq!(max_ok.len(), 255);
30699        is_git_ref_name(&max_ok).unwrap();
30700        let too_long = "a".repeat(256);
30701        assert_eq!(too_long.len(), 256);
30702        let err = is_git_ref_name(&too_long).unwrap_err();
30703        assert!(err.contains("255"), "got: {err:?}");
30704        assert!(err.contains("256"), "got: {err:?}");
30705    }
30706
30707    #[test]
30708    fn git_ref_name_qualified_prefix_diagnostic_quotes_leaf() {
30709        // Diagnostic-shape pin: the `refs/heads/` / `refs/tags/`
30710        // rejection arm enumerates the leaf the author probably
30711        // meant, so the author's grep target is the *intended*
30712        // refname literal rather than the (rejected) qualified form.
30713        // Pinned across both prefixes so a future relaxation that
30714        // drops the leaf-suggestion surfaces here.
30715        for (qualified, leaf) in [
30716            ("refs/heads/main", "main"),
30717            ("refs/tags/v0.1.0", "v0.1.0"),
30718            ("refs/heads/feature/checkout", "feature/checkout"),
30719        ] {
30720            let err = is_git_ref_name(qualified).unwrap_err();
30721            assert!(
30722                err.contains(&format!("{leaf:?}")),
30723                "qualified ref {qualified:?} diagnostic must quote the leaf \
30724                 {leaf:?}; got {err:?}"
30725            );
30726        }
30727    }
30728
30729    // ── is_git_ref_name canonical-OID-shape partition arm ────────────────
30730
30731    #[test]
30732    fn git_ref_name_rejects_canonical_sha1_oid() {
30733        // The fail-before-pass-after pin on the canonical SHA-1 OID
30734        // partition arm: a 40-char lowercase-hex string is the shape
30735        // `is_git_oid` accepts, so `is_git_ref_name` must reject it.
30736        // Until this arm landed `is_git_ref_name` accepted every
30737        // 40-char lowercase-hex string (pure hex carries none of the
30738        // forbidden refname characters, no `..`/`@{`/`/`-prefix/
30739        // `/`-suffix/`.lock`-suffix/`refs/heads/`-prefix), silently
30740        // breaking the cross-axis partition the
30741        // [`DepSource::validate`] gate routes the `:fonte` axes
30742        // through and admitting `:tag "deadbeef…"` /
30743        // `:branch "deadbeef…"` as legitimate refnames — the
30744        // canonical paste-from-`git show --format=%H` mis-slot
30745        // footgun. The diagnostic names the `:rev` axis so the author
30746        // grep-fixes in one edit.
30747        for oid in [
30748            "0123456789abcdef0123456789abcdef01234567",
30749            "deadbeefcafebabe0123456789abcdef01234567",
30750            "ffffffffffffffffffffffffffffffffffffffff",
30751            "0000000000000000000000000000000000000000",
30752        ] {
30753            assert_eq!(oid.len(), GIT_OID_SHA1_LEN);
30754            let err = is_git_ref_name(oid).unwrap_err();
30755            assert!(
30756                err.contains("OID") && err.contains(":rev"),
30757                "canonical SHA-1 OID {oid:?} must surface a diagnostic \
30758                 naming OID + `:rev`; got {err:?}"
30759            );
30760            assert!(
30761                err.contains("SHA-1"),
30762                "canonical SHA-1 OID {oid:?} diagnostic must name the \
30763                 hash algorithm; got {err:?}"
30764            );
30765        }
30766    }
30767
30768    #[test]
30769    fn git_ref_name_rejects_canonical_sha256_oid() {
30770        // The fail-before-pass-after pin on the canonical SHA-256 OID
30771        // partition arm — Git 2.42+ `extensions.objectFormat = sha256`
30772        // mode. 64-char lowercase-hex strings are equally OID-shaped
30773        // and must surface the same `:rev`-axis diagnostic. Pinned
30774        // separately from SHA-1 so a future relaxation that only
30775        // catches one width surfaces here.
30776        let sha256_zeros = "0".repeat(GIT_OID_SHA256_LEN);
30777        let sha256_ones = "f".repeat(GIT_OID_SHA256_LEN);
30778        let sha256_mixed = format!("deadbeefcafebabe{}", "0123456789abcdef".repeat(3));
30779        for oid in [&sha256_zeros, &sha256_ones, &sha256_mixed] {
30780            assert_eq!(oid.len(), GIT_OID_SHA256_LEN);
30781            let err = is_git_ref_name(oid).unwrap_err();
30782            assert!(
30783                err.contains("OID") && err.contains(":rev"),
30784                "canonical SHA-256 OID {oid:?} must surface a \
30785                 diagnostic naming OID + `:rev`; got {err:?}"
30786            );
30787            assert!(
30788                err.contains("SHA-256"),
30789                "canonical SHA-256 OID {oid:?} diagnostic must name \
30790                 the hash algorithm; got {err:?}"
30791            );
30792        }
30793    }
30794
30795    #[test]
30796    fn git_ref_name_partition_excludes_off_by_one_lengths() {
30797        // Boundary pin: lengths that *aren't* exactly 40 or 64 hex
30798        // characters are NOT canonical OIDs, so the partition arm
30799        // must not fire — they remain accepted as refnames (consistent
30800        // with `is_git_oid` rejecting them on its exact-width check).
30801        // Abbreviated OIDs (`"c0ffee0"`, 7-char prefix) are ambiguous
30802        // across repository history and `is_git_oid` rejects them
30803        // separately, but they're legitimate refname shapes per `git
30804        // check-ref-format`, so `is_git_ref_name` accepts them here.
30805        // Pinned across the 39/41/63/65-char and abbreviated arms so
30806        // a future widening of the partition arm to "any hex-shaped
30807        // value" surfaces here as a regression rather than silently
30808        // rejecting valid refnames.
30809        for accept in [
30810            // 39 hex chars — one short of SHA-1 width.
30811            "0123456789abcdef0123456789abcdef0123456",
30812            // 41 hex chars — one over SHA-1 width.
30813            "0123456789abcdef0123456789abcdef012345670",
30814            // 63 hex chars — one short of SHA-256 width.
30815            &"a".repeat(63),
30816            // 65 hex chars — one over SHA-256 width.
30817            &"a".repeat(65),
30818            // Abbreviated 7-char SHA — the `git log --short` width.
30819            "c0ffee0",
30820            // Pure-numeric 8-char (looks vaguely SHA-shaped but
30821            // isn't canonical-width).
30822            "00000000",
30823        ] {
30824            is_git_ref_name(accept).unwrap_or_else(|e| {
30825                panic!(
30826                    "off-canonical-width hex-shaped value {accept:?} \
30827                     (len {len}) must still pass is_git_ref_name — \
30828                     the partition arm is exact-width 40/64, not a \
30829                     prefix or pattern: {e:?}",
30830                    len = accept.len()
30831                )
30832            });
30833        }
30834    }
30835
30836    #[test]
30837    fn git_ref_name_partition_excludes_uppercase_canonical_widths() {
30838        // Boundary pin: the partition arm targets the canonical
30839        // *lowercase-hex* OID shape `git rev-parse HEAD` /
30840        // `git show --format=%H` emit. Uppercase or mixed-case
30841        // 40/64-char hex strings are legitimate refnames per
30842        // `git check-ref-format` (uppercase letters are admitted in
30843        // refnames), so `is_git_ref_name` accepts them here; the
30844        // `:rev` axis separately rejects uppercase OIDs via
30845        // [`is_git_oid`]'s lowercase-only contract — so neither
30846        // axis silently admits an uppercase-hex value cross-slot.
30847        // Pinned across both widths + both uppercase variants so a
30848        // future relaxation of either predicate surfaces here.
30849        for accept in [
30850            // Uppercase 40-char hex — passes is_git_ref_name (valid
30851            // refname), rejected by is_git_oid on lowercase contract.
30852            "DEADBEEFCAFEBABE0123456789ABCDEF01234567",
30853            // Mixed case 40-char hex.
30854            "DeadBeefCafeBabe0123456789abcdef01234567",
30855            // Uppercase 64-char hex.
30856            &"A".repeat(64),
30857        ] {
30858            is_git_ref_name(accept).unwrap_or_else(|e| {
30859                panic!(
30860                    "uppercase canonical-width hex value {accept:?} \
30861                     must still pass is_git_ref_name — the partition \
30862                     arm targets lowercase-canonical only (uppercase \
30863                     is a legitimate refname character per \
30864                     git-check-ref-format); the `:rev` axis catches \
30865                     uppercase via is_git_oid's lowercase contract: \
30866                     {e:?}"
30867                )
30868            });
30869            // And confirm is_git_oid rejects it on the lowercase arm
30870            // (so neither axis silently admits the value).
30871            let oid_err = is_git_oid(accept).unwrap_err();
30872            assert!(
30873                oid_err.contains("lowercase") || oid_err.contains("uppercase"),
30874                "uppercase hex value {accept:?} must be rejected by \
30875                 is_git_oid on its lowercase contract; got {oid_err:?}"
30876            );
30877        }
30878    }
30879
30880    #[test]
30881    fn git_ref_name_partition_arm_fires_before_per_byte_scan() {
30882        // Order pin: the partition arm runs after the length check
30883        // but before the per-byte refname-character scan, so a
30884        // canonical-OID-shaped value surfaces the `:rev`-axis
30885        // diagnostic rather than (e.g.) falling through to a generic
30886        // per-component arm. Pinned via a canonical OID — pure hex
30887        // can't violate any of the per-byte / `..` / `@{` / `/` /
30888        // `.lock` / `refs/heads/` arms (which is precisely why the
30889        // partition arm is needed), so position-wise this pin
30890        // forecloses a future refactor that splits the partition arm
30891        // across the scan (where uppercase / mixed-case canonical-
30892        // width values would silently route through one branch).
30893        let oid = "0123456789abcdef0123456789abcdef01234567";
30894        let err = is_git_ref_name(oid).unwrap_err();
30895        // The diagnostic mentions OID + `:rev`; it does NOT contain
30896        // any of the per-byte-arm needle substrings the
30897        // `git_ref_name_rejects_each_arm_with_substring_pinned_reason`
30898        // sweep pins, structurally — canonical OIDs can't violate
30899        // those arms.
30900        assert!(err.contains("OID"), "got: {err:?}");
30901        assert!(err.contains(":rev"), "got: {err:?}");
30902    }
30903
30904    #[test]
30905    fn git_ref_name_rejects_leading_hyphen_cli_arg_injection() {
30906        // The CLI-arg-injection arm pin on the `:tag` / `:branch` axis.
30907        // Git's `check-ref-format` grammar admits a leading `-` (the
30908        // byte is a legitimate kebab continuation), so every prior
30909        // shape arm passes the value through; the diagnostic moves
30910        // the gate to the subprocess-argument boundary the resolver
30911        // consumes. Pinned across the canonical CLI-arg-injection
30912        // shapes — short-flag-shaped `"-X"`, long-option-shaped
30913        // `"-stable"`, git-config-injection-shaped
30914        // `"-c=core.merge=ours"`, the canonical
30915        // `"--upload-pack=…"` long-flag form, and the
30916        // `"--config"`-shape repeat-arg form — every shape would
30917        // silently escape `git checkout --quiet --detach <ref>` (the
30918        // resolver's invocation in `caixa-resolver/src/git.rs:41`,
30919        // no `--` argument-list terminator) and get reinterpreted by
30920        // `git checkout`'s argument parser. Peer with the
30921        // `is_git_repo_url` leading-`-` arm (same vector on the
30922        // sibling `:repo` axis), `is_cargo_feature_name` leading-`-`
30923        // arm, and `is_dns_1123_label` leading-`-` arm — the
30924        // substrate-wide "no leading `-` anywhere in a typed
30925        // single-token string slot routed through a subprocess
30926        // argument" invariant is now structurally consistent across
30927        // every value-shape-gated typed surface.
30928        for s in [
30929            "-X",                     // short-flag-shape
30930            "-stable",                // long-option-shape
30931            "-c=core.merge=ours",     // git-config-injection-shape
30932            "--upload-pack=cat /etc", // long-flag with-value
30933            "--config",               // repeat-arg shape
30934            "-",                      // degenerate single-byte
30935        ] {
30936            let err = is_git_ref_name(s)
30937                .err()
30938                .unwrap_or_else(|| panic!("git ref {s:?} must be rejected"));
30939            assert!(
30940                err.contains("`-`"),
30941                "git ref {s:?} reason must surface the leading-`-` arm: {err:?}"
30942            );
30943            assert!(
30944                err.contains("CLI-argument-injection"),
30945                "git ref {s:?} reason must name the CLI-argument-injection \
30946                 vector: {err:?}"
30947            );
30948        }
30949        // Positive control: a mid-name `-` (the canonical kebab
30950        // separator) passes — `"v0-1-0"`, `"feature-x"`, `"main-2"`
30951        // — pinning that the arm only fires at the leading position,
30952        // not anywhere else.
30953        for s in ["v0-1-0", "feature-x", "main-2"] {
30954            is_git_ref_name(s).unwrap_or_else(|e| {
30955                panic!("mid-name `-` ref {s:?} must pass the leading-`-` arm: {e:?}")
30956            });
30957        }
30958    }
30959
30960    #[test]
30961    fn git_ref_name_leading_hyphen_fires_before_per_byte_scan() {
30962        // Cascade-precedence pin: a `"-flag\n"` value carries both a
30963        // leading `-` and an embedded `\n` control byte; the leading-`-`
30964        // arm fires first (the byte sits at the leading position the
30965        // arm probes, before the per-byte cascade loop's control-byte
30966        // arm). Mirrors the order pin
30967        // `git_ref_name_partition_arm_fires_before_per_byte_scan`
30968        // establishes on the canonical-OID partition arm — both
30969        // pre-loop arms structurally precede the per-byte scan.
30970        let err = is_git_ref_name("-flag\n").unwrap_err();
30971        assert!(err.contains("`-`"), "got: {err:?}");
30972        assert!(
30973            !err.contains("control character"),
30974            "leading-`-` arm must fire before the control-byte per-byte arm: {err:?}"
30975        );
30976    }
30977
30978    #[test]
30979    fn git_ref_name_leading_hyphen_fires_after_canonical_oid_partition() {
30980        // Cascade-precedence pin: the partition arm structurally
30981        // precedes the leading-`-` arm because a canonical OID shape
30982        // (40 / 64 lowercase hex bytes) cannot start with `-` — the
30983        // byte sets are disjoint, so the precedence pin is a no-op at
30984        // value level. The pin matters only at the diagnostic-shape
30985        // level — it ensures a future codec round-trip that
30986        // synthesizes a probe-as-both value (impossible today;
30987        // possible if the OID partition arm ever relaxes its byte
30988        // set) surfaces the more self-locating `:rev`-mis-slot
30989        // diagnostic rather than the broader CLI-arg-injection one.
30990        let oid = "0123456789abcdef0123456789abcdef01234567";
30991        let err = is_git_ref_name(oid).unwrap_err();
30992        assert!(err.contains("OID"), "got: {err:?}");
30993        assert!(
30994            !err.contains("CLI-argument-injection"),
30995            "OID partition arm must precede leading-`-` arm: {err:?}"
30996        );
30997    }
30998
30999    // ── is_git_oid — `:fonte :rev` value-shape predicate ────────────────
31000
31001    #[test]
31002    fn git_oid_canonical_widths_match_sha1_and_sha256() {
31003        // The single-source-of-truth pin on the two canonical widths.
31004        // Drift between the predicate's accepted widths and the const
31005        // values would surface here as a build error, not as a silent
31006        // round-trip break at the renderer layer. Mirrors
31007        // `wasm32_memory_cap_matches_parsed_4_gib` (9d49a3a) — the
31008        // constant equality pin keeps the contract one place.
31009        assert_eq!(GIT_OID_SHA1_LEN, 40);
31010        assert_eq!(GIT_OID_SHA256_LEN, 64);
31011        // Doubled width: SHA-256 is exactly twice SHA-1 in hex char
31012        // count (256 / 4 = 64; 160 / 4 = 40). Pinned so a future
31013        // hash-algorithm widening reads the relationship here.
31014        assert_eq!(GIT_OID_SHA256_LEN, GIT_OID_SHA1_LEN * 2 - 16);
31015    }
31016
31017    #[test]
31018    fn git_oid_accepts_canonical_sha1() {
31019        // Positive control on the SHA-1 OID width: 40 lowercase hex
31020        // characters — the canonical `git rev-parse HEAD` emission
31021        // shape every realistic pleme-io upstream uses today. The all-
31022        // `f` boundary is the lexicographically-largest OID (a real
31023        // commit's hash could land here, and the predicate accepts it
31024        // because it's structurally a valid OID — the null-OID
31025        // sentinel arm partitions the all-`0` boundary only, not the
31026        // all-`f` one).
31027        is_git_oid("0123456789abcdef0123456789abcdef01234567").unwrap();
31028        is_git_oid("deadbeefcafebabe0123456789abcdef01234567").unwrap();
31029        is_git_oid("ffffffffffffffffffffffffffffffffffffffff").unwrap();
31030    }
31031
31032    #[test]
31033    fn git_oid_accepts_canonical_sha256() {
31034        // Positive control on the SHA-256 OID width: 64 lowercase hex
31035        // characters — `git`'s `extensions.objectFormat = sha256`
31036        // emission (GA since Git 2.42 / Oct 2023). Doubled SHA-1 width.
31037        let sha256_one = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
31038        assert_eq!(sha256_one.len(), 64);
31039        is_git_oid(sha256_one).unwrap();
31040        let sha256_fs = "f".repeat(64);
31041        is_git_oid(&sha256_fs).unwrap();
31042    }
31043
31044    #[test]
31045    fn git_oid_rejects_null_oid_sentinel_sha1() {
31046        // Canonical "I copy-pasted the no-such-commit sentinel out of
31047        // `git update-ref --stdin` docs / pre-receive hook example"
31048        // footgun on the SHA-1 width — the all-zero 40-char hex
31049        // string is git's `null OID` sentinel (used to indicate ref
31050        // create / delete in update-ref flows) and never names a real
31051        // commit in any repo's object database. Until the null-OID
31052        // arm landed it passed every other shape arm (canonical
31053        // length, lowercase hex) and surfaced at `git fetch <remote>
31054        // 0000…0000` time with a quoting-confused "couldn't find
31055        // remote ref" error far from the source caixa.lisp, with the
31056        // lacre's content-address locked to a `git:0000…0000` closure
31057        // that never equals any upstream's actual `HEAD`. The
31058        // diagnostic carries the `40` width verbatim so a future
31059        // SHA-256 fixture surfaces the same arm at the doubled width
31060        // boundary.
31061        let null_sha1 = "0".repeat(40);
31062        let err = is_git_oid(&null_sha1).unwrap_err();
31063        assert!(
31064            err.contains("null-OID sentinel"),
31065            "reason must name the sentinel: {err}",
31066        );
31067        assert!(err.contains("40"), "reason must name the width: {err}",);
31068        assert!(
31069            err.contains("no-such-commit") || err.contains("update-ref"),
31070            "reason must reference git's null-OID semantics: {err}",
31071        );
31072    }
31073
31074    #[test]
31075    fn git_oid_rejects_null_oid_sentinel_sha256() {
31076        // Same sentinel on the SHA-256 width — `git`'s
31077        // `extensions.objectFormat = sha256` mode (GA Git 2.42 / Oct
31078        // 2023) carries the same null-OID semantics on the doubled
31079        // 64-char width. Pinned separately so a future relaxation that
31080        // only catches the SHA-1 width surfaces here, peer with the
31081        // SHA-1 / SHA-256 pair-pinning posture
31082        // `git_oid_accepts_canonical_sha1` /
31083        // `git_oid_accepts_canonical_sha256` already establishes for
31084        // the positive controls.
31085        let null_sha256 = "0".repeat(64);
31086        let err = is_git_oid(&null_sha256).unwrap_err();
31087        assert!(
31088            err.contains("null-OID sentinel"),
31089            "reason must name the sentinel: {err}",
31090        );
31091        assert!(err.contains("64"), "reason must name the width: {err}",);
31092    }
31093
31094    #[test]
31095    fn git_oid_null_oid_fires_after_length_and_hex_arms() {
31096        // Cascade-precedence pin: the null-OID arm runs *after* the
31097        // length + character-class arms, so an off-by-one-length all-
31098        // zeros value surfaces the narrower `abbreviated` diagnostic
31099        // (the length arm's own reason wording) before the structural
31100        // null-OID diagnostic, and an uppercase all-zeros value (which
31101        // can't actually exist — `0` has no case — but pinned via the
31102        // mixed-case-but-non-null fixture) routes the same way. The
31103        // null-OID arm is the *fourth* arm, structurally the
31104        // lexicographic-content-arm after length and per-byte
31105        // character-class.
31106        let off_by_one_zeros = "0".repeat(41);
31107        let err = is_git_oid(&off_by_one_zeros).unwrap_err();
31108        assert!(
31109            err.contains("abbreviated"),
31110            "off-by-one-length all-zeros surfaces length arm first: {err}",
31111        );
31112        // The all-`f` 40-char value — same boundary class as null-OID
31113        // but at the opposite hex extreme — passes the predicate,
31114        // confirming the null-OID arm doesn't over-fire on lexicographic
31115        // boundaries.
31116        is_git_oid("ffffffffffffffffffffffffffffffffffffffff").unwrap();
31117    }
31118
31119    #[test]
31120    fn git_oid_rejects_empty_defensively() {
31121        // The predicate is called from `crate::dep::DepSource::validate`
31122        // only after the per-axis `FontePinEmpty` arm has fired at
31123        // validate time; re-checking here keeps the predicate usable
31124        // from any future call site without an empty-precondition
31125        // footgun. Same defensive empty-check `is_dns_1123_label`,
31126        // `is_gateway_api_http_path`, `is_wit_world_ref`,
31127        // `is_nats_subject`, `is_wasi_keyvalue_slot`, and
31128        // `is_git_ref_name` carry at their call sites.
31129        let err = is_git_oid("").unwrap_err();
31130        assert!(err.contains("empty"), "got: {err:?}");
31131    }
31132
31133    #[test]
31134    fn git_oid_rejects_each_arm_with_substring_pinned_reason() {
31135        // Substrate-side diagnostic-shape pin: each grammar arm
31136        // surfaces its own distinct reason substring. Pinned here so a
31137        // future reason-wording rephrase that drops any of these
31138        // substrings surfaces at this one place, not piecemeal across
31139        // every per-axis test sweep. Mirrors
31140        // `git_ref_name_rejects_each_arm_with_substring_pinned_reason`,
31141        // `wasi_kv_slot_rejects_each_arm_with_substring_pinned_reason`,
31142        // and `nats_subject_rejects_each_arm_with_substring_pinned_reason`
31143        // on the peer predicates.
31144        for (s, needle) in [
31145            // Abbreviated 7-char prefix — the canonical `git log
31146            // --short` paste-from-release-notes footgun.
31147            ("c0ffee0", "abbreviated"),
31148            // Abbreviated 12-char prefix — `git log --short=12`.
31149            ("c0ffee001234", "abbreviated"),
31150            // Off-by-one above SHA-1 width.
31151            ("0123456789abcdef0123456789abcdef012345670", "abbreviated"),
31152            // Off-by-one below SHA-256 width.
31153            (
31154                "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde",
31155                "abbreviated",
31156            ),
31157            // Off-by-one above SHA-256 width.
31158            (
31159                "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0",
31160                "abbreviated",
31161            ),
31162            // Uppercase SHA-1 — `git porcelain` lowercases on output.
31163            ("DEADBEEFCAFEBABE0123456789ABCDEF01234567", "uppercase"),
31164            // Mixed-case SHA-1 — same path as pure-uppercase; the first
31165            // uppercase byte fires the arm.
31166            ("deadbeefCAFEbabe0123456789abcdef01234567", "uppercase"),
31167            // Non-hex character at exact SHA-1 length — the cross-axis
31168            // mis-slot footgun (a refname-style char landing in `:rev`).
31169            // `g` is the first non-hex byte; the non-hex arm fires
31170            // ahead of any other rule. The hyphen / colon / slash arms
31171            // are the same path on the same predicate.
31172            ("g123456789abcdef0123456789abcdef01234567", "non-hex"),
31173            ("0123456789abcdef-123456789abcdef01234567", "non-hex"),
31174            ("0123456789abcdef/123456789abcdef01234567", "non-hex"),
31175            ("0123456789abcdef:123456789abcdef01234567", "non-hex"),
31176            // Whitespace inside an otherwise-SHA-shaped value (length
31177            // 41 — fails the length arm first; pinned to ensure the
31178            // diagnostic surfaces *some* parser wording).
31179            ("0123456789abcdef0123456789abcdef01234567 ", "abbreviated"),
31180        ] {
31181            let err = is_git_oid(s)
31182                .err()
31183                .unwrap_or_else(|| panic!("git OID {s:?} must be rejected"));
31184            assert!(
31185                err.contains(needle),
31186                "git OID {s:?} reason must contain {needle:?}; got {err:?}"
31187            );
31188        }
31189    }
31190
31191    #[test]
31192    fn git_oid_rejects_at_canonical_width_boundaries() {
31193        // Boundary pin on the two canonical widths simultaneously: 39
31194        // (below SHA-1), 40 (SHA-1 exactly), 41 (just above), 63 (just
31195        // below SHA-256), 64 (SHA-256 exactly), 65 (just above). Pinned
31196        // so a future relaxation that admits "close enough" widths
31197        // surfaces here. The failing-length fixtures use all-zero hex
31198        // so only the length arm fires (the null-OID sentinel arm is
31199        // structurally downstream of the length arm — a non-canonical
31200        // length fires the abbreviated diagnostic before the null
31201        // diagnostic). The passing-length fixtures use a non-null hex
31202        // value so the null-OID arm doesn't fire (the all-zero
31203        // canonical-width value is the sentinel and is rejected by its
31204        // own arm, pinned in `git_oid_rejects_null_oid_sentinel_*`).
31205        let nonzero_sha1 = "0123456789abcdef0123456789abcdef01234567";
31206        assert_eq!(nonzero_sha1.len(), 40);
31207        let nonzero_sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
31208        assert_eq!(nonzero_sha256.len(), 64);
31209        for (len, ok) in [
31210            (1usize, false),
31211            (7, false),
31212            (39, false),
31213            (40, true),
31214            (41, false),
31215            (63, false),
31216            (64, true),
31217            (65, false),
31218            (128, false),
31219        ] {
31220            let s = if ok && len == 40 {
31221                nonzero_sha1.to_string()
31222            } else if ok && len == 64 {
31223                nonzero_sha256.to_string()
31224            } else {
31225                "0".repeat(len)
31226            };
31227            let result = is_git_oid(&s);
31228            if ok {
31229                result.unwrap_or_else(|e| panic!("len {len} must pass: {e:?}"));
31230            } else {
31231                let err = result.expect_err(&format!("len {len} must fail"));
31232                assert!(
31233                    err.contains("abbreviated") || err.contains(&len.to_string()),
31234                    "len {len} reason must name the offending length or surface \
31235                     the abbreviation arm, got {err:?}"
31236                );
31237            }
31238        }
31239    }
31240
31241    #[test]
31242    fn git_oid_rejection_is_disjoint_from_ref_name_acceptance() {
31243        // Structural pin: the two predicates partition the `:fonte`
31244        // pin axes — every canonical refname is rejected by
31245        // `is_git_oid`, and every canonical OID is rejected by
31246        // `is_git_ref_name`. The intersection of the two valid sets
31247        // is exactly the empty set. Drift here = a value that passes
31248        // both predicates would land at *both* axes silently, defeating
31249        // the structural "cross-axis mis-slot is a build error"
31250        // contract. Pinned with a representative cross-set so a future
31251        // predicate weakening surfaces here.
31252        let canonical_refnames = [
31253            "v0.1.0",
31254            "main",
31255            "feature/checkout",
31256            "release-1.0",
31257            "user-1/feat-x-v2",
31258        ];
31259        for refname in canonical_refnames {
31260            is_git_ref_name(refname).unwrap_or_else(|e| {
31261                panic!("setup: canonical refname {refname:?} must pass is_git_ref_name: {e:?}")
31262            });
31263            assert!(
31264                is_git_oid(refname).is_err(),
31265                "canonical refname {refname:?} must NOT pass is_git_oid \
31266                 (predicate-partition pin)"
31267            );
31268        }
31269        let canonical_oids = [
31270            "0123456789abcdef0123456789abcdef01234567",
31271            "deadbeefcafebabe0123456789abcdef01234567",
31272            "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
31273        ];
31274        for oid in canonical_oids {
31275            is_git_oid(oid).unwrap_or_else(|e| {
31276                panic!("setup: canonical OID {oid:?} must pass is_git_oid: {e:?}")
31277            });
31278            assert!(
31279                is_git_ref_name(oid).is_err(),
31280                "canonical OID {oid:?} must NOT pass is_git_ref_name \
31281                 (predicate-partition pin)"
31282            );
31283        }
31284    }
31285
31286    // ── is_sandboxed_relative_path — `:behavior :on-*` + `:upgrade-from ─
31287    // ── :state-change :script` value-shape predicate ────────────────────
31288
31289    #[test]
31290    fn sandboxed_relative_path_accepts_canonical_relative_paths() {
31291        // Positive controls: every documented authoring shape across
31292        // the two existing call sites (`:behavior :on-init` / `:on-call`
31293        // / `:on-cast` / `:on-info` / `:on-state-change` / `:on-terminate`
31294        // and `:upgrade-from :state-change :script`) — bare filename,
31295        // standard `lib/` subdirectory, deeply-nested migrations
31296        // subdirectory, sibling-folder-shaped path, and explicit
31297        // current-dir-relative-prefixed path. Pin every leg so a
31298        // future tightening that rejects any of these (e.g. demanding
31299        // a `lib/` prefix specifically, or forbidding the explicit
31300        // `./` segment) surfaces here as a test-failure at the predicate
31301        // boundary, not piecemeal across per-axis call sites.
31302        for relpath in [
31303            "init.lisp",
31304            "lib/init.lisp",
31305            "lib/handlers.lisp",
31306            "lib/migrations/v01-to-v02.lisp",
31307            "callbacks/on_call.lisp",
31308            "./lib/init.lisp",
31309            "a",
31310        ] {
31311            is_sandboxed_relative_path(Path::new(relpath)).unwrap_or_else(|v| {
31312                panic!("canonical relative path {relpath:?} must pass, got {v:?}")
31313            });
31314        }
31315    }
31316
31317    #[test]
31318    fn sandboxed_relative_path_rejects_empty() {
31319        // The fail-before-pass-after pin on the empty arm. Both
31320        // `PathBuf::new()` (no bytes) and `PathBuf::from("")` (empty
31321        // string) hit the `as_os_str().is_empty()` precondition; both
31322        // resolve to `root` under `root.join(p)` and silently point the
31323        // `LisleLoader` at the project directory rather than a file.
31324        assert_eq!(
31325            is_sandboxed_relative_path(Path::new("")),
31326            Err(PathShapeViolation::Empty)
31327        );
31328        let blank = PathBuf::new();
31329        assert_eq!(
31330            is_sandboxed_relative_path(&blank),
31331            Err(PathShapeViolation::Empty)
31332        );
31333    }
31334
31335    #[test]
31336    fn sandboxed_relative_path_rejects_absolute() {
31337        // The fail-before-pass-after pin on the absolute arm. Sweep
31338        // the canonical sandbox-escape paste-from-shell-prompt
31339        // footguns: an `/etc/...` Lunatic-style sandbox bypass, a
31340        // user-home leak that the renderer's `root.join(p)` would
31341        // silently replace, the project-relative-shaped `/lib/...`
31342        // typo where the author meant `lib/...` without a leading
31343        // slash, and the bare root `/`. `Path::join` replaces the
31344        // base with an absolute right-hand side, so every one of
31345        // these resolves verbatim to outside the caixa root regardless
31346        // of where the layout checker rooted itself.
31347        for abs in [
31348            "/etc/passwd",
31349            "/home/user/escape.lisp",
31350            "/lib/init.lisp",
31351            "/",
31352        ] {
31353            assert_eq!(
31354                is_sandboxed_relative_path(Path::new(abs)),
31355                Err(PathShapeViolation::Absolute),
31356                "absolute path {abs:?} must surface as PathShapeViolation::Absolute"
31357            );
31358        }
31359    }
31360
31361    #[test]
31362    fn sandboxed_relative_path_rejects_parent_escape_at_every_position() {
31363        // The fail-before-pass-after pin on the parent-escape arm.
31364        // Position sweep — `..` as a leading component (the canonical
31365        // "I meant the sibling caixa" mis-author), as a mid-path
31366        // component (the canonical "lib/../../escape" path-traversal
31367        // that's structurally identical regardless of how many `..`
31368        // segments stack), as a trailing component (lib/.., resolving
31369        // to the project root via a delayed escape), and the bare `..`
31370        // (project parent directory). Each must surface as
31371        // `PathShapeViolation::ParentEscape` regardless of position —
31372        // pinned per-position so a future relaxation that only
31373        // checks one position surfaces at this one place, not
31374        // piecemeal across per-axis call sites.
31375        for escape in [
31376            "../sibling/init.lisp",
31377            "lib/../../escaped.lisp",
31378            "lib/..",
31379            "..",
31380            "lib/handlers/../../escape.lisp",
31381        ] {
31382            assert_eq!(
31383                is_sandboxed_relative_path(Path::new(escape)),
31384                Err(PathShapeViolation::ParentEscape),
31385                "parent-escape path {escape:?} must surface as \
31386                 PathShapeViolation::ParentEscape"
31387            );
31388        }
31389    }
31390
31391    #[test]
31392    fn sandboxed_relative_path_arm_ordering_is_empty_absolute_parent_escape() {
31393        // Order pin: the predicate evaluates Empty → Absolute →
31394        // ParentEscape — the same arm-ordering both inlined call sites
31395        // followed verbatim (b0c8389 `BehaviorSpec::validate`'s
31396        // `validate_callback_path`, 26da2c7
31397        // `UpgradeInstruction::StateChange::validate`). A future
31398        // reordering would silently flip which diagnostic the per-axis
31399        // wrapper surfaces (e.g. an absolute-and-empty hybrid value
31400        // would suddenly raise `Absolute` instead of `Empty`). Pinned
31401        // here so a future reorder surfaces at the predicate boundary.
31402        //
31403        // The empty case can't *also* be absolute (empty paths are
31404        // relative-by-construction) or parent-escaping, so the
31405        // empty-first ordering only matters relative to the OS-string
31406        // emptiness check vs. the absolute-prefix check. Pin the two
31407        // legs that *can* compose: an absolute path with `..` segments
31408        // must raise `Absolute` (not `ParentEscape`); an absolute-but-
31409        // not-parent-escaping path must also raise `Absolute`. The
31410        // arm-ordering pin is structural — every parent-escape case
31411        // tested above is relative, so the ParentEscape arm is reached
31412        // only when both Empty and Absolute arms have been cleared.
31413        assert_eq!(
31414            is_sandboxed_relative_path(Path::new("/etc/../passwd")),
31415            Err(PathShapeViolation::Absolute),
31416            "absolute path with `..` segments must surface as Absolute (not \
31417             ParentEscape) — Empty → Absolute → ParentEscape arm-ordering pin"
31418        );
31419    }
31420
31421    #[test]
31422    fn sandboxed_relative_path_distinguishes_curdir_from_parent_escape() {
31423        // Boundary pin: `Component::CurDir` (`.`) is NOT a sandbox
31424        // escape — `root.join("./lib/x.lisp")` resolves to
31425        // `root/lib/x.lisp`, identical to `root.join("lib/x.lisp")`,
31426        // so `./` segments must pass the predicate. The arm-ordering
31427        // check above pins that `Component::ParentDir` is the only
31428        // escape vector caught here. Pinned separately so a future
31429        // tightening that *does* reject `.` segments (e.g. requiring
31430        // canonical normalized form) lands at this one predicate.
31431        is_sandboxed_relative_path(Path::new("./lib/init.lisp")).unwrap();
31432        is_sandboxed_relative_path(Path::new("lib/./handlers.lisp")).unwrap();
31433    }
31434
31435    #[test]
31436    fn sandboxed_relative_path_violations_are_distinct_variants() {
31437        // Diagnostic-shape pin: the three `PathShapeViolation` variants
31438        // are distinct enum tags so each per-axis caller can match-and-
31439        // wrap into its own typed `*Path` / `*Script` variant without
31440        // a string-parse step (the trap [`is_dns_1123_label`] etc.
31441        // avoid by returning `Result<(), String>` — but the path-shape
31442        // callers were already split three ways across `BehaviorError`
31443        // / `UpgradeError`, so a `String` return would *regress* the
31444        // diagnostic shape rather than preserve it). The PartialEq /
31445        // Copy / Hash derives on `PathShapeViolation` are pinned here
31446        // so a future API rework reads the requirement off this test.
31447        let v1 = PathShapeViolation::Empty;
31448        let v2 = PathShapeViolation::Absolute;
31449        let v3 = PathShapeViolation::ParentEscape;
31450        assert_ne!(v1, v2);
31451        assert_ne!(v2, v3);
31452        assert_ne!(v1, v3);
31453        // Copy + Eq round-trip: predicate consumers like
31454        // `BehaviorSpec::validate` and `UpgradeInstruction::validate`
31455        // pattern-match on the variant without consuming it.
31456        let v_copy = v1;
31457        assert_eq!(v1, v_copy);
31458    }
31459
31460    #[test]
31461    fn sandboxed_relative_path_matches_inlined_call_site_semantics() {
31462        // End-to-end pin: every value the two pre-lift inline gates
31463        // (`BehaviorSpec::validate_callback_path` and
31464        // `UpgradeInstruction::StateChange::validate`'s inline arms)
31465        // accepted-or-rejected must surface from the lifted predicate
31466        // with identically-classified violation tags. Drift here would
31467        // mean a previously-accepted authoring shape would suddenly
31468        // fail (or vice versa) silently across the lift commit. Pinned
31469        // by sweeping the canonical authoring shapes both pre-lift call
31470        // sites' tests cover.
31471        // Pre-lift accepts (must still pass):
31472        for accept in [
31473            "lib/init.lisp",
31474            "lib/handlers.lisp",
31475            "lib/migrations.lisp",
31476            "lib/cleanup.lisp",
31477            "lib/migrations/v01-to-v02.lisp",
31478            "callbacks/handle_call.lisp",
31479        ] {
31480            is_sandboxed_relative_path(Path::new(accept))
31481                .unwrap_or_else(|v| panic!("pre-lift accept {accept:?} regressed, got {v:?}"));
31482        }
31483        // Pre-lift rejects (must still reject, with the same tag):
31484        let cases: &[(&str, PathShapeViolation)] = &[
31485            ("", PathShapeViolation::Empty),
31486            ("/etc/passwd", PathShapeViolation::Absolute),
31487            ("/etc/migrations.lisp", PathShapeViolation::Absolute),
31488            (
31489                "../sibling/migrations.lisp",
31490                PathShapeViolation::ParentEscape,
31491            ),
31492            ("lib/../../escaped.lisp", PathShapeViolation::ParentEscape),
31493        ];
31494        for (reject, expected) in cases {
31495            assert_eq!(
31496                is_sandboxed_relative_path(Path::new(reject)).unwrap_err(),
31497                *expected,
31498                "pre-lift reject {reject:?} must classify as {expected:?}"
31499            );
31500        }
31501    }
31502
31503    // ── is_lisp_extension — `:behavior :on-*` + `:upgrade-from ───────────
31504    // ── :state-change :script` file-type predicate ───────────────────────
31505
31506    #[test]
31507    fn lisp_extension_accepts_canonical_shapes() {
31508        // Positive controls: every documented authoring shape across
31509        // both existing call sites — bare filename, standard `lib/`
31510        // subdirectory, deeply-nested migrations subdirectory,
31511        // explicit current-dir-relative prefix, mid-path `./`
31512        // segment, single-letter stem, and the multi-dot stem
31513        // (`lib/migrations/v.0.1.lisp`) an author might use to
31514        // encode the migration's `:from` version into the filename.
31515        // The predicate only inspects the terminating extension —
31516        // `Path::extension()` returns the substring after the final
31517        // `.` — so the multi-dot stem is structurally accepted
31518        // because the final extension is still `lisp`. Drift here =
31519        // a future tightening that rejects any of these surfaces as
31520        // a test-failure at the predicate boundary, not piecemeal
31521        // across per-axis call sites (`BehaviorSpec::validate`,
31522        // `UpgradeInstruction::StateChange::validate`).
31523        for relpath in [
31524            "init.lisp",
31525            "lib/init.lisp",
31526            "lib/handlers.lisp",
31527            "lib/migrations.lisp",
31528            "lib/migrations/v01-to-v02.lisp",
31529            "./lib/init.lisp",
31530            "lib/./handlers.lisp",
31531            "lib/migrations/v.0.1.lisp",
31532            "a.lisp",
31533        ] {
31534            assert!(
31535                is_lisp_extension(Path::new(relpath)),
31536                "canonical `.lisp` shape {relpath:?} must pass is_lisp_extension"
31537            );
31538        }
31539    }
31540
31541    #[test]
31542    fn lisp_extension_rejects_no_extension() {
31543        // The fail-before-pass-after pin on the no-extension shape.
31544        // A path with no `.` component (`Path::extension()` returns
31545        // `None`) is the canonical "I declared the slot but forgot
31546        // the `.lisp` extension" authoring footgun. The wasm-engine's
31547        // `tatara_lisp::read` consumer can't infer the file type from
31548        // the path alone, so the gate refuses the value at validate
31549        // time.
31550        for relpath in [
31551            "lib/init",
31552            "init",
31553            "lib/handlers",
31554            "lib/migrations/v01-to-v02",
31555            "a",
31556        ] {
31557            assert!(
31558                !is_lisp_extension(Path::new(relpath)),
31559                "no-extension shape {relpath:?} must fail is_lisp_extension"
31560            );
31561        }
31562    }
31563
31564    #[test]
31565    fn lisp_extension_rejects_wrong_extension() {
31566        // Wrong-extension sweep: the canonical authoring footguns
31567        // an author might drag in from the workspace tree (`.txt`,
31568        // `.md`, `.json`, `.yaml`, `.toml`), the `.rs` shape that
31569        // an IDE auto-complete might propose, the `.lisp.bak` shape
31570        // an editor might leave behind (the predicate only inspects
31571        // the *terminating* extension — `Path::extension()` returns
31572        // `bak` here, not `lisp.bak` — so the gate refuses it as a
31573        // no-`.lisp` final extension), and the `.lispx` / `.lis`
31574        // near-miss shapes that a typo would produce. Each must
31575        // fail the predicate — the wasm-engine's `tatara_lisp::read`
31576        // consumer rejects all of these at hot-upgrade migration /
31577        // instance-start time.
31578        for relpath in [
31579            "lib/init.rs",
31580            "lib/init.txt",
31581            "lib/init.md",
31582            "lib/init.json",
31583            "lib/init.yaml",
31584            "lib/init.toml",
31585            "lib/init.lisp.bak",
31586            "lib/init.lispx",
31587            "lib/init.lis",
31588        ] {
31589            assert!(
31590                !is_lisp_extension(Path::new(relpath)),
31591                "wrong-extension shape {relpath:?} must fail is_lisp_extension"
31592            );
31593        }
31594    }
31595
31596    #[test]
31597    fn lisp_extension_is_case_sensitive() {
31598        // Strict lowercase pin: every case-folded shape a
31599        // case-insensitive volume's existence check would match the
31600        // on-disk file must still fail the predicate — the
31601        // canonical-form codec emits lowercase `.lisp` verbatim, so
31602        // a case-folded shape mismatches the round-trip-stable
31603        // canonical form (THEORY.md §V.2.7 render-determinism).
31604        // Same case-sensitive discipline the byte-size / duration
31605        // codecs and every other shape-gate predicate in `render.rs`
31606        // (label / scheme / unit boundaries) carry. Pinned at the
31607        // predicate boundary so any future case-folding regression
31608        // surfaces here rather than piecemeal across per-axis call
31609        // sites.
31610        for relpath in [
31611            "lib/init.LISP",
31612            "lib/init.Lisp",
31613            "lib/init.LiSp",
31614            "lib/init.lISP",
31615            "lib/init.LISp",
31616        ] {
31617            assert!(
31618                !is_lisp_extension(Path::new(relpath)),
31619                "case-folded `.lisp` shape {relpath:?} must fail is_lisp_extension \
31620                 (strict lowercase, render-determinism pin)"
31621            );
31622        }
31623    }
31624
31625    #[test]
31626    fn lisp_extension_constant_matches_predicate() {
31627        // Cross-pin: the [`LISP_SOURCE_EXTENSION`] const and the
31628        // predicate's accepted set are the same single source of
31629        // truth. Drift would let a future renderer / per-axis
31630        // wrapper emit `.<const>` while the predicate accepts only
31631        // `.lisp` (or vice versa), silently breaking the
31632        // round-trip-stable canonical form. Pinned by constructing
31633        // a path from the const and round-tripping through the
31634        // predicate.
31635        assert_eq!(LISP_SOURCE_EXTENSION, "lisp");
31636        let p = PathBuf::from(format!("lib/init.{LISP_SOURCE_EXTENSION}"));
31637        assert!(
31638            is_lisp_extension(&p),
31639            "path constructed from LISP_SOURCE_EXTENSION must pass is_lisp_extension"
31640        );
31641    }
31642
31643    #[test]
31644    fn lisp_extension_matches_inlined_call_site_semantics() {
31645        // End-to-end pin: every value the pre-lift inline gate
31646        // (`BehaviorSpec::validate_callback_path`, c97815a) accepted-
31647        // or-rejected must surface from the lifted predicate
31648        // identically. Drift here would mean a previously-accepted
31649        // authoring shape would suddenly fail (or vice versa)
31650        // silently across the lift commit. Sweeps the canonical
31651        // authoring shapes the pre-lift call site's tests covered
31652        // verbatim.
31653        // Pre-lift accepts (must still pass):
31654        for accept in [
31655            "lib/init.lisp",
31656            "lib/handlers.lisp",
31657            "lib/migrations/v01-to-v02.lisp",
31658            "init.lisp",
31659            "a.lisp",
31660            "./lib/init.lisp",
31661            "lib/./handlers.lisp",
31662            "lib/migrations/v.0.1.lisp",
31663        ] {
31664            assert!(
31665                is_lisp_extension(Path::new(accept)),
31666                "pre-lift accept {accept:?} regressed"
31667            );
31668        }
31669        // Pre-lift rejects (must still reject):
31670        for reject in [
31671            "lib/init",
31672            "init",
31673            "lib/init.rs",
31674            "lib/init.txt",
31675            "lib/init.lisp.bak",
31676            "lib/init.lispx",
31677            "lib/init.LISP",
31678            "lib/init.Lisp",
31679        ] {
31680            assert!(
31681                !is_lisp_extension(Path::new(reject)),
31682                "pre-lift reject {reject:?} regressed"
31683            );
31684        }
31685    }
31686
31687    // ── is_computeunit_yaml_extension — `:servicos` compound-suffix predicate ───
31688
31689    #[test]
31690    fn computeunit_yaml_extension_accepts_canonical_shapes() {
31691        // Positive controls: every canonical authoring shape every
31692        // in-tree fixture and the `Caixa::template` scaffold use. The
31693        // predicate inspects the final file-name component and checks
31694        // for the compound `.computeunit.yaml` suffix with at least
31695        // one byte of stem preceding it.
31696        for relpath in [
31697            "servicos/demo.computeunit.yaml",
31698            "servicos/hello-rio.computeunit.yaml",
31699            "servicos/my-service.computeunit.yaml",
31700            "servicos/a.computeunit.yaml",
31701            "./servicos/demo.computeunit.yaml",
31702            "servicos/./demo.computeunit.yaml",
31703            "servicos/sub/nested.computeunit.yaml",
31704            "servicos/v0.1.computeunit.yaml",
31705        ] {
31706            assert!(
31707                is_computeunit_yaml_extension(Path::new(relpath)),
31708                "canonical `.computeunit.yaml` shape {relpath:?} must pass \
31709                 is_computeunit_yaml_extension"
31710            );
31711        }
31712    }
31713
31714    #[test]
31715    fn computeunit_yaml_extension_rejects_no_extension() {
31716        // No-extension shape — the canonical "I declared the slot
31717        // but forgot the `.computeunit.yaml` suffix" footgun. The
31718        // peer caixa-helm / caixa-flux `serde_yaml::from_str`
31719        // consumer can't infer the file type from the path alone, so
31720        // the gate refuses the value at validate time.
31721        for relpath in ["servicos/demo", "demo", "servicos/sub/nested"] {
31722            assert!(
31723                !is_computeunit_yaml_extension(Path::new(relpath)),
31724                "no-extension shape {relpath:?} must fail \
31725                 is_computeunit_yaml_extension"
31726            );
31727        }
31728    }
31729
31730    #[test]
31731    fn computeunit_yaml_extension_rejects_wrong_extension() {
31732        // Wrong-extension sweep across the canonical authoring footguns
31733        // an author might drag in from the workspace tree — bare
31734        // `.yaml` (the canonical "I forgot the `.computeunit` segment"
31735        // typo), `.yml` (Helm-shorthand leak), `.json` (FluxCD
31736        // bundle leak), `.toml` (Cargo workspace leak), `.txt`
31737        // / `.md` (paste-from-doc footguns), `.yaml.bak` (editor
31738        // backup), the near-miss `.computeunit.yam` / `.computeunit.yamls`
31739        // typo, and the off-by-one-segment `computeunit-yaml`
31740        // / `computeunit_yaml` shapes. Each must fail the predicate.
31741        for relpath in [
31742            "servicos/demo.yaml",
31743            "servicos/demo.yml",
31744            "servicos/demo.json",
31745            "servicos/demo.toml",
31746            "servicos/demo.txt",
31747            "servicos/demo.md",
31748            "servicos/demo.computeunit.yaml.bak",
31749            "servicos/demo.computeunit.yam",
31750            "servicos/demo.computeunit.yamls",
31751            "servicos/demo.computeunit",
31752            "servicos/demo-computeunit.yaml",
31753            "servicos/demo_computeunit.yaml",
31754        ] {
31755            assert!(
31756                !is_computeunit_yaml_extension(Path::new(relpath)),
31757                "wrong-extension shape {relpath:?} must fail \
31758                 is_computeunit_yaml_extension"
31759            );
31760        }
31761    }
31762
31763    #[test]
31764    fn computeunit_yaml_extension_is_case_sensitive() {
31765        // Strict lowercase pin: every case-folded shape a
31766        // case-insensitive volume's existence check would match the
31767        // on-disk file must still fail the predicate — the canonical-
31768        // form codec emits lowercase `.computeunit.yaml` verbatim, so
31769        // a case-folded shape mismatches the round-trip-stable
31770        // canonical form (THEORY.md §V.2.7 render-determinism). Same
31771        // case-sensitive discipline the byte-size / duration codecs
31772        // and the peer `is_lisp_extension` predicate carry.
31773        for relpath in [
31774            "servicos/demo.ComputeUnit.yaml",
31775            "servicos/demo.COMPUTEUNIT.yaml",
31776            "servicos/demo.computeunit.YAML",
31777            "servicos/demo.computeunit.Yaml",
31778            "servicos/demo.COMPUTEUNIT.YAML",
31779        ] {
31780            assert!(
31781                !is_computeunit_yaml_extension(Path::new(relpath)),
31782                "case-folded `.computeunit.yaml` shape {relpath:?} must fail \
31783                 is_computeunit_yaml_extension (strict lowercase, \
31784                 render-determinism pin)"
31785            );
31786        }
31787    }
31788
31789    #[test]
31790    fn computeunit_yaml_extension_rejects_empty_stem() {
31791        // Degenerate hidden-file shape: a file name exactly equal to
31792        // the suffix (`.computeunit.yaml` — no stem preceding the
31793        // suffix) is the structural "Servico declared with no
31794        // identity" footgun. The substrate identifies each ComputeUnit
31795        // by the file-stem segment that precedes `.computeunit.yaml`
31796        // (the rendered `lareira-<stem>` Helm chart, the per-Servico
31797        // `metadata.name`, the M3 `:contratos` membership lookup), so
31798        // an empty stem leaves the Servico unidentifiable. Predicate
31799        // pin: the `name.len() > SUFFIX.len()` bound rejects the
31800        // hidden-file shape at the predicate boundary.
31801        for relpath in [".computeunit.yaml", "servicos/.computeunit.yaml"] {
31802            assert!(
31803                !is_computeunit_yaml_extension(Path::new(relpath)),
31804                "empty-stem shape {relpath:?} must fail \
31805                 is_computeunit_yaml_extension"
31806            );
31807        }
31808    }
31809
31810    #[test]
31811    fn computeunit_yaml_extension_constant_matches_predicate() {
31812        // Cross-pin: the [`COMPUTEUNIT_YAML_SUFFIX`] const and the
31813        // predicate's accepted set are the same single source of
31814        // truth. Drift would let a future renderer / per-axis wrapper
31815        // emit `<stem><const>` while the predicate accepts only
31816        // `.computeunit.yaml` (or vice versa), silently breaking the
31817        // round-trip-stable canonical form. Pinned by constructing a
31818        // path from the const and round-tripping through the
31819        // predicate. Mirrors the peer
31820        // `lisp_extension_constant_matches_predicate` pin.
31821        assert_eq!(COMPUTEUNIT_YAML_SUFFIX, ".computeunit.yaml");
31822        let p = PathBuf::from(format!("servicos/demo{COMPUTEUNIT_YAML_SUFFIX}"));
31823        assert!(
31824            is_computeunit_yaml_extension(&p),
31825            "path constructed from COMPUTEUNIT_YAML_SUFFIX must pass \
31826             is_computeunit_yaml_extension"
31827        );
31828    }
31829
31830    // ── is_cargo_feature_name — shared `:caracteristicas` feature-name predicate ──
31831
31832    #[test]
31833    fn cargo_feature_name_accepts_canonical_forms() {
31834        // Substrate-side pin: the predicate accepts every canonical Cargo
31835        // feature name shape `:caracteristicas` entries carry. Drift between
31836        // this list and the per-axis `dep::tests::validate_accepts_canonical_caracteristicas`
31837        // positive-set sweep surfaces here — one source of truth for the
31838        // rule. Includes single-token (`http`), kebab-case (`runtime-tokio`),
31839        // snake-case (`derive_macros`), namespaced-dot (`tokio.full`),
31840        // version-suffix (`v0.1`), `+`-separated (`http+json`), leading
31841        // underscore (`_internal`), doubled-underscore (`__private`),
31842        // and digit-starting (`v0_1`) — the canonical authoring shapes
31843        // every realistic Cargo feature in the pleme-io ecosystem uses.
31844        for s in [
31845            "http",
31846            "json",
31847            "derive",
31848            "serde",
31849            "serde_json",
31850            "runtime-tokio",
31851            "tokio.full",
31852            "v0.1",
31853            "v1",
31854            "http+json",
31855            "_internal",
31856            "__private",
31857            "default",
31858            "rt-multi-thread",
31859            "12factor",
31860            "feat.v2",
31861            "client+server",
31862        ] {
31863            is_cargo_feature_name(s)
31864                .unwrap_or_else(|e| panic!("canonical Cargo feature name {s:?} must pass: {e:?}"));
31865        }
31866    }
31867
31868    #[test]
31869    fn cargo_feature_name_rejects_each_arm_with_substring_pinned_reason() {
31870        // Substrate-side diagnostic-shape pin: each grammar arm
31871        // surfaces its own distinct reason substring. Pinned here so a
31872        // future reason-wording rephrase that drops any of these
31873        // substrings surfaces at this one place, not piecemeal across
31874        // every per-axis test sweep. Mirrors
31875        // `git_repo_url`'s and `git_ref_name`'s arm-substring sweeps
31876        // on the peer predicates.
31877        for (s, needle) in [
31878            // Leading `+` — the canonical paste-from-`+optional-feature`
31879            // activation-form-in-feature-name-slot footgun.
31880            ("+http", "`+`"),
31881            // Leading `-` — kebab-leak / CLI-arg-injection adjacent.
31882            ("-json", "`-`"),
31883            // Leading `.` — dotted-version-suffix-as-feature-name typo.
31884            (".feat", "`.`"),
31885            // Whitespace inside — multi-token blob.
31886            ("http feature", "whitespace"),
31887            // Tab inside.
31888            ("http\tjson", "whitespace"),
31889            // Leading whitespace — paste-from-aligned-doc.
31890            (" http", "whitespace"),
31891            // Comma — list-separator-belongs-to-list-grammar.
31892            ("http,json", "`,`"),
31893            // Forward slash — Cargo's `dep/feat` namespaced-dep syntax.
31894            ("http/json", "`/`"),
31895            // Question mark — URL-reserved.
31896            ("http?", "`?`"),
31897            // Hash — URL-reserved.
31898            ("http#frag", "`#`"),
31899            // Embedded control character.
31900            ("http\x01json", "control character"),
31901            // Newline — paste-from-multiline-doc.
31902            ("http\njson", "control character"),
31903            // DEL byte (0x7F).
31904            ("http\x7fjson", "control character"),
31905            // Non-ASCII byte — un-percent-encoded character.
31906            ("caf\u{e9}", "non-ASCII"),
31907            // Non-ASCII at first byte.
31908            ("\u{e9}feat", "non-ASCII"),
31909            // Forbidden punctuation in the continuation set.
31910            ("http@1", "invalid character"),
31911            ("http&json", "invalid character"),
31912            ("http=v1", "invalid character"),
31913        ] {
31914            let err = is_cargo_feature_name(s)
31915                .err()
31916                .unwrap_or_else(|| panic!("Cargo feature name {s:?} must be rejected"));
31917            assert!(
31918                err.contains(needle),
31919                "Cargo feature name {s:?} reason must contain {needle:?}; got {err:?}"
31920            );
31921        }
31922    }
31923
31924    #[test]
31925    fn cargo_feature_name_rejects_empty_defensively() {
31926        // The predicate is called from `crate::dep::Dep::validate_caracteristicas`
31927        // only after the per-axis `CaracteristicaEmpty` arm has fired
31928        // at validate time; re-checking here keeps the predicate usable
31929        // from any future call site without an empty-precondition
31930        // footgun. Same defensive empty-check `is_dns_1123_label`,
31931        // `is_gateway_api_http_path`, `is_wit_world_ref`,
31932        // `is_nats_subject`, `is_wasi_keyvalue_slot`, `is_git_ref_name`,
31933        // `is_git_oid`, and `is_git_repo_url` carry at their call sites.
31934        let err = is_cargo_feature_name("").unwrap_err();
31935        assert!(err.contains("empty"), "got: {err:?}");
31936    }
31937
31938    #[test]
31939    fn cargo_feature_name_rejects_at_65_byte_boundary() {
31940        // The 64-byte cap pin — both the boundary-exceeding case and
31941        // the boundary-accepting case in one place, so a future cap
31942        // shift surfaces both arms simultaneously, mirroring
31943        // `dns_1123_label_rejects_at_64_byte_boundary`,
31944        // `gateway_api_http_path_rejects_at_1025_byte_boundary`,
31945        // `wit_world_ref_rejects_at_129_byte_boundary`,
31946        // `nats_subject_rejects_at_257_byte_boundary`,
31947        // `wasi_kv_slot_rejects_at_513_byte_boundary`, and
31948        // `git_ref_name_rejects_at_256_byte_boundary` on the peer
31949        // predicates. Constructed as a single all-`a` token so only
31950        // the cap arm fires.
31951        let max_ok = "a".repeat(CARGO_FEATURE_NAME_MAX_LEN);
31952        assert_eq!(max_ok.len(), 64);
31953        is_cargo_feature_name(&max_ok).unwrap();
31954        let too_long = "a".repeat(CARGO_FEATURE_NAME_MAX_LEN + 1);
31955        assert_eq!(too_long.len(), 65);
31956        let err = is_cargo_feature_name(&too_long).unwrap_err();
31957        assert!(err.contains("64"), "got: {err:?}");
31958        assert!(err.contains("65"), "got: {err:?}");
31959    }
31960
31961    #[test]
31962    fn cargo_feature_name_first_byte_diagnostics_name_the_leading_char() {
31963        // Diagnostic-shape pin: the leading-character rejection arms
31964        // name the specific punctuation (`+`, `-`, `.`) verbatim so the
31965        // author's grep target is unambiguous. Pinned across the three
31966        // canonical leading-char footguns so a future relaxation that
31967        // drops any of the three surfaces here. The `+`-arm's wording
31968        // additionally points the author at the canonical Cargo
31969        // `+<feature>` activation-form-vs-feature-name discipline so
31970        // the paste-from-doc footgun lands its remediation in the
31971        // diagnostic itself.
31972        let err_plus = is_cargo_feature_name("+http").unwrap_err();
31973        assert!(err_plus.contains("`+`"), "got: {err_plus:?}");
31974        assert!(
31975            err_plus.contains("activation"),
31976            "got: {err_plus:?} (must name the Cargo +<feature> activation-form)"
31977        );
31978        let err_hyphen = is_cargo_feature_name("-json").unwrap_err();
31979        assert!(err_hyphen.contains("`-`"), "got: {err_hyphen:?}");
31980        let err_dot = is_cargo_feature_name(".feat").unwrap_err();
31981        assert!(err_dot.contains("`.`"), "got: {err_dot:?}");
31982    }
31983
31984    // ── is_spdx_expression_shape — shared `:licenca` SPDX-expression predicate ──
31985
31986    #[test]
31987    fn spdx_expression_shape_accepts_canonical_forms() {
31988        // Substrate-side pin: the predicate accepts every canonical
31989        // SPDX expression shape the `:licenca` axis carries. Drift
31990        // between this list and the per-axis
31991        // `manifest::tests::validate_licenca_accepts_canonical_expressions`
31992        // positive-set sweep surfaces here — one source of truth for
31993        // the rule. Covers single-license, `OR`/`AND`-compound,
31994        // `WITH`-exception, parenthesis-grouped, `+`-suffix, and
31995        // `LicenseRef-` / `DocumentRef-:LicenseRef-` shapes.
31996        for s in [
31997            "MIT",
31998            "Apache-2.0",
31999            "BSD-3-Clause",
32000            "MPL-2.0",
32001            "GPL-3.0-or-later",
32002            "GPL-2.0+",
32003            "Apache-2.0 OR MIT",
32004            "Apache-2.0 AND MIT",
32005            "Apache-2.0 WITH LLVM-exception",
32006            "(MIT OR Apache-2.0) AND BSD-3-Clause",
32007            "(MIT OR Apache-2.0) AND BSD-3-Clause AND ISC",
32008            "LicenseRef-MyLicense",
32009            "DocumentRef-spdx-tool:LicenseRef-MIT-Style",
32010            "x",
32011        ] {
32012            is_spdx_expression_shape(s)
32013                .unwrap_or_else(|e| panic!("canonical SPDX expression {s:?} must pass: {e:?}"));
32014        }
32015    }
32016
32017    #[test]
32018    fn spdx_expression_shape_rejects_each_arm_with_substring_pinned_reason() {
32019        // Substrate-side diagnostic-shape pin: each alphabet arm
32020        // surfaces its own distinct reason substring. Pinned here so a
32021        // future reason-wording rephrase that drops any of these
32022        // substrings surfaces at this one place, not piecemeal across
32023        // every per-axis test sweep. Mirrors
32024        // `cargo_feature_name_rejects_each_arm_with_substring_pinned_reason`
32025        // on the peer predicate.
32026        for (s, needle) in [
32027            // Leading whitespace — paste-from-aligned-doc.
32028            (" MIT", "whitespace"),
32029            // Trailing whitespace — paste-from-doc.
32030            ("MIT ", "whitespace"),
32031            // Tab inside — tab-from-aligned-doc.
32032            ("MIT\tOR Apache-2.0", "tab"),
32033            // Embedded control character.
32034            ("MIT\x01OR Apache-2.0", "control character"),
32035            // Newline — paste-from-multiline-doc.
32036            ("MIT\nOR Apache-2.0", "control character"),
32037            // CRLF — paste-from-multiline-doc.
32038            ("MIT\rApache-2.0", "control character"),
32039            // DEL byte (0x7F).
32040            ("MIT\x7fApache-2.0", "control character"),
32041            // Non-ASCII byte — smart-quote paste.
32042            ("MIT\u{a0}OR Apache-2.0", "non-ASCII"),
32043            // Non-ASCII at first byte — fullwidth letter.
32044            ("\u{ff2d}IT", "non-ASCII"),
32045            // Underscore — snake-case-instead-of-kebab-case typo.
32046            ("Apache_2.0", "`_`"),
32047            // Comma — list-separator-belongs-to-list-grammar.
32048            ("MIT, Apache-2.0", "`,`"),
32049            // Forward slash — colloquial dual-license idiom.
32050            ("MIT/Apache-2.0", "`/`"),
32051            // Semicolon — list-separator confusion.
32052            ("MIT; Apache-2.0", "`;`"),
32053            // Forbidden punctuation in the alphabet.
32054            ("MIT@1.0", "invalid character"),
32055            ("MIT&Apache-2.0", "invalid character"),
32056            ("MIT=Apache-2.0", "invalid character"),
32057            ("MIT*1.0", "invalid character"),
32058        ] {
32059            let err = is_spdx_expression_shape(s)
32060                .err()
32061                .unwrap_or_else(|| panic!("SPDX expression {s:?} must be rejected"));
32062            assert!(
32063                err.contains(needle),
32064                "SPDX expression {s:?} reason must contain {needle:?}; got {err:?}"
32065            );
32066        }
32067    }
32068
32069    #[test]
32070    fn spdx_expression_shape_rejects_empty_defensively() {
32071        // The predicate is called from `crate::Caixa::validate_licenca`
32072        // only after the per-axis `LicencaEmpty` arm has fired at
32073        // validate time; re-checking here keeps the predicate usable
32074        // from any future call site without an empty-precondition
32075        // footgun. Same defensive empty-check `is_dns_1123_label`,
32076        // `is_gateway_api_http_path`, `is_wit_world_ref`,
32077        // `is_nats_subject`, `is_wasi_keyvalue_slot`,
32078        // `is_git_ref_name`, `is_git_oid`, `is_git_repo_url`, and
32079        // `is_cargo_feature_name` carry at their call sites.
32080        let err = is_spdx_expression_shape("").unwrap_err();
32081        assert!(err.contains("empty"), "got: {err:?}");
32082    }
32083
32084    #[test]
32085    fn spdx_expression_shape_rejects_at_257_byte_boundary() {
32086        // The 256-byte cap pin — both the boundary-exceeding case and
32087        // the boundary-accepting case in one place, so a future cap
32088        // shift surfaces both arms simultaneously, mirroring the peer
32089        // cap-boundary pins. Constructed as a single all-`a` token so
32090        // only the cap arm fires (256 `a` bytes is alphabet-valid).
32091        let max_ok = "a".repeat(SPDX_EXPRESSION_MAX_LEN);
32092        assert_eq!(max_ok.len(), 256);
32093        is_spdx_expression_shape(&max_ok).unwrap();
32094        let too_long = "a".repeat(SPDX_EXPRESSION_MAX_LEN + 1);
32095        assert_eq!(too_long.len(), 257);
32096        let err = is_spdx_expression_shape(&too_long).unwrap_err();
32097        assert!(err.contains("256"), "got: {err:?}");
32098        assert!(err.contains("257"), "got: {err:?}");
32099    }
32100
32101    // ── is_chart_description_shape — shared `:descricao` chart-description predicate ──
32102
32103    #[test]
32104    fn chart_description_shape_accepts_canonical_forms() {
32105        // Substrate-side pin: the predicate accepts every canonical
32106        // chart-description shape the `:descricao` axis carries.
32107        // Drift between this list and the per-axis
32108        // `manifest::tests::validate_descricao_accepts_canonical_summary`
32109        // positive-set sweep surfaces here — one source of truth for
32110        // the rule. Covers ASCII summaries, the Unicode `→` from the
32111        // canonical Rust→wasm fixture, and the Unicode `—` em-dash
32112        // from the `Caixa::template` scaffold every `feira init`
32113        // emits.
32114        for s in [
32115            "Canonical Rust→wasm32-wasip2 caixa Servico.",
32116            "Checkout flow.",
32117            "AWS provider caixa for tatara-lisp",
32118            "FIXME — describe this caixa",
32119            "x",
32120        ] {
32121            is_chart_description_shape(s)
32122                .unwrap_or_else(|e| panic!("canonical chart description {s:?} must pass: {e:?}"));
32123        }
32124    }
32125
32126    #[test]
32127    fn chart_description_shape_rejects_each_arm_with_substring_pinned_reason() {
32128        // Substrate-side diagnostic-shape pin: each arm surfaces its
32129        // own distinct reason substring. Pinned here so a future
32130        // reason-wording rephrase that drops any of these substrings
32131        // surfaces at this one place, not piecemeal across every
32132        // per-axis test sweep. Mirrors
32133        // `spdx_expression_shape_rejects_each_arm_with_substring_pinned_reason`
32134        // on the peer predicate.
32135        for (s, needle) in [
32136            // Leading whitespace — paste-from-aligned-doc.
32137            (" Checkout flow.", "whitespace"),
32138            // Trailing whitespace — paste-from-doc.
32139            ("Checkout flow. ", "whitespace"),
32140            // Tab inside — tab-from-aligned-doc.
32141            ("Checkout\tflow.", "tab"),
32142            // Newline — paste-from-multiline-doc.
32143            ("Checkout\nflow.", "newline"),
32144            // Carriage return — paste-from-Windows-CRLF-doc.
32145            ("Checkout\rflow.", "carriage return"),
32146            // NUL byte — paste-from-binary-blob.
32147            ("Checkout\x00flow.", "control character"),
32148            // BEL byte — paste-from-binary-blob.
32149            ("Checkout\x07flow.", "control character"),
32150            // ESC byte — paste-from-binary-blob.
32151            ("Checkout\x1bflow.", "control character"),
32152            // DEL byte (0x7F).
32153            ("Checkout\x7fflow.", "control character"),
32154        ] {
32155            let err = is_chart_description_shape(s)
32156                .err()
32157                .unwrap_or_else(|| panic!("chart description {s:?} must be rejected"));
32158            assert!(
32159                err.contains(needle),
32160                "chart description {s:?} reason must contain {needle:?}; got {err:?}"
32161            );
32162        }
32163    }
32164
32165    #[test]
32166    fn chart_description_shape_accepts_unicode() {
32167        // Positive control on the non-ASCII arm: the predicate must
32168        // accept Unicode beyond the ASCII alphabet — the canonical
32169        // pleme-io descricao fixtures carry `→` (U+2192) and `—`
32170        // (U+2014), and every downstream consumer (YAML 1.2, Helm v3,
32171        // every chart-aware UI) round-trips Unicode losslessly.
32172        // Mirrors the spdx-rejects-non-ASCII arm by inverting it — a
32173        // future tightening that bans non-ASCII bytes would regress
32174        // every canonical fixture and surface here as a regression.
32175        for s in [
32176            "Canonical Rust→wasm32-wasip2",
32177            "FIXME — describe this caixa",
32178            "Caixa pour le projet tâche",
32179            "日本語の説明",
32180            "naïve",
32181        ] {
32182            is_chart_description_shape(s)
32183                .unwrap_or_else(|e| panic!("Unicode chart description {s:?} must pass: {e:?}"));
32184        }
32185    }
32186
32187    #[test]
32188    fn chart_description_shape_rejects_empty_defensively() {
32189        // The predicate is called from `crate::Caixa::validate_descricao`
32190        // only after the per-axis `DescricaoEmpty` arm has fired at
32191        // validate time; re-checking here keeps the predicate usable
32192        // from any future call site without an empty-precondition
32193        // footgun. Same defensive empty-check `is_dns_1123_label`,
32194        // `is_gateway_api_http_path`, `is_wit_world_ref`,
32195        // `is_nats_subject`, `is_wasi_keyvalue_slot`,
32196        // `is_git_ref_name`, `is_git_oid`, `is_git_repo_url`,
32197        // `is_cargo_feature_name`, and `is_spdx_expression_shape`
32198        // carry at their call sites.
32199        let err = is_chart_description_shape("").unwrap_err();
32200        assert!(err.contains("empty"), "got: {err:?}");
32201    }
32202
32203    #[test]
32204    fn chart_description_shape_rejects_at_513_byte_boundary() {
32205        // The 512-byte cap pin — both the boundary-exceeding case and
32206        // the boundary-accepting case in one place, so a future cap
32207        // shift surfaces both arms simultaneously, mirroring the peer
32208        // cap-boundary pins. Constructed as a single all-`a` token so
32209        // only the cap arm fires (512 `a` bytes is alphabet-valid).
32210        let max_ok = "a".repeat(CHART_DESCRIPTION_MAX_LEN);
32211        assert_eq!(max_ok.len(), 512);
32212        is_chart_description_shape(&max_ok).unwrap();
32213        let too_long = "a".repeat(CHART_DESCRIPTION_MAX_LEN + 1);
32214        assert_eq!(too_long.len(), 513);
32215        let err = is_chart_description_shape(&too_long).unwrap_err();
32216        assert!(err.contains("512"), "got: {err:?}");
32217        assert!(err.contains("513"), "got: {err:?}");
32218    }
32219
32220    #[test]
32221    fn chart_description_shape_rejects_each_unicode_bidi_override_codepoint() {
32222        // The Trojan Source (CVE-2021-42574) arm — pins every UAX #9
32223        // bidirectional-override / isolate format codepoint as a
32224        // structural rejection on the typed `:descricao` axis. The
32225        // per-byte non-ASCII pass deliberately admits Unicode letters
32226        // / em-dash / arrows because the canonical fixtures carry them
32227        // (`Canonical Rust→wasm32-wasip2`, `FIXME — describe this
32228        // caixa`); only the typed codepoint scan catches the nine
32229        // bidi-override codepoints that flip the rendered visual order
32230        // of every following character, so a future drop of any one
32231        // arm here surfaces as a `must be rejected` panic at this one
32232        // place rather than as a silent regression downstream. Each
32233        // case carries an alphabet-valid prefix + suffix so only the
32234        // bidi-override arm fires.
32235        for (cp, name) in [
32236            ('\u{202A}', "U+202A"),
32237            ('\u{202B}', "U+202B"),
32238            ('\u{202C}', "U+202C"),
32239            ('\u{202D}', "U+202D"),
32240            ('\u{202E}', "U+202E"),
32241            ('\u{2066}', "U+2066"),
32242            ('\u{2067}', "U+2067"),
32243            ('\u{2068}', "U+2068"),
32244            ('\u{2069}', "U+2069"),
32245        ] {
32246            let s = format!("alice{cp}bob");
32247            let err = is_chart_description_shape(&s)
32248                .err()
32249                .unwrap_or_else(|| panic!("chart description with {name} must be rejected"));
32250            assert!(
32251                err.contains(name),
32252                "chart description reason for {name} must name the codepoint verbatim; got {err:?}"
32253            );
32254            assert!(
32255                err.contains("bidirectional-override")
32256                    || err.contains("Unicode bidi")
32257                    || err.contains("Trojan Source"),
32258                "chart description reason for {name} must name the Trojan-Source banner; \
32259                 got {err:?}"
32260            );
32261        }
32262    }
32263
32264    #[test]
32265    fn chart_description_shape_accepts_pure_rtl_text_without_bidi_override() {
32266        // Positive control on the bidi-override arm: pure visual
32267        // right-to-left scripts (Hebrew, Arabic) decode to non-bidi-
32268        // override codepoints and the predicate must accept them
32269        // natively — banning all RTL would regress every Hebrew /
32270        // Arabic-authored caixa, which the substrate explicitly
32271        // supports via the non-ASCII byte arm. The structural axis the
32272        // bidi-override arm closes is the explicit direction-mark
32273        // codepoint, not the RTL script itself.
32274        for s in [
32275            // Hebrew word (RTL script, no bidi-override codepoint).
32276            "שלום",
32277            // Arabic word (RTL script, no bidi-override codepoint).
32278            "مرحبا",
32279            // Mixed LTR / RTL caixa — the canonical multilingual
32280            // description shape every YAML 1.2 + Helm v3 + Artifact
32281            // Hub consumer round-trips losslessly.
32282            "Caixa para שלום",
32283        ] {
32284            is_chart_description_shape(s).unwrap_or_else(|e| {
32285                panic!("pure-RTL chart description {s:?} must pass without bidi override: {e:?}")
32286            });
32287        }
32288    }
32289
32290    #[test]
32291    fn chart_description_shape_rejects_each_unicode_line_break_codepoint() {
32292        // The non-ASCII Unicode line-break arm — pins each of the three
32293        // UAX #14 / YAML 1.1 §4.1 line-break codepoints outside the
32294        // ASCII `\n` / `\r` bytes already caught at the per-byte pass.
32295        // Each case carries an alphabet-valid prefix + suffix so only
32296        // the line-break arm fires; the per-byte `\n` / `\r` arms
32297        // would shadow the codepoint scan if the line-break helper
32298        // accepted single-byte ASCII line terminators. A future drop
32299        // of any one arm here surfaces as a `must be rejected` panic
32300        // at this one place rather than as a silent regression
32301        // through YAML 1.1-compat downstream consumers (go-yaml v2 /
32302        // Helm v3 / kubectl). Mirrors the peer
32303        // `chart_maintainer_name_shape_rejects_each_unicode_line_break_codepoint`
32304        // on the sibling predicate — both predicates route through the
32305        // same lifted `find_unicode_line_break` helper.
32306        for (cp, name) in [
32307            ('\u{0085}', "U+0085"),
32308            ('\u{2028}', "U+2028"),
32309            ('\u{2029}', "U+2029"),
32310        ] {
32311            let s = format!("first line{cp}second line");
32312            let err = is_chart_description_shape(&s)
32313                .err()
32314                .unwrap_or_else(|| panic!("chart description with {name} must be rejected"));
32315            assert!(
32316                err.contains(name),
32317                "chart description reason for {name} must name the codepoint verbatim; got {err:?}"
32318            );
32319            assert!(
32320                err.contains("line-break") || err.contains("UAX #14") || err.contains("YAML 1.1"),
32321                "chart description reason for {name} must name the Unicode-line-break banner; \
32322                 got {err:?}"
32323            );
32324        }
32325    }
32326
32327    #[test]
32328    fn chart_description_shape_accepts_non_line_break_unicode() {
32329        // Positive control on the line-break arm: the predicate must
32330        // accept every non-line-break Unicode shape the canonical
32331        // fixtures carry. Pinned alongside the per-codepoint rejection
32332        // sweep so a future helper widening that accidentally rejects
32333        // a non-line-break codepoint (the structural-floor regression
32334        // class) surfaces here as a single-source-of-truth pin. The
32335        // canonical multilingual descriptions, RTL text, em-dash and
32336        // arrows must all pass.
32337        for s in [
32338            "Canonical Rust→wasm32-wasip2 caixa Servico.",
32339            "FIXME — describe this caixa",
32340            "Caixa para שלום",
32341            "日本語の説明テスト",
32342            // U+00A0 NO-BREAK SPACE is NOT a line-break codepoint
32343            // (UAX #14 class GL — Glue, non-breaking) — must pass.
32344            "Caixa\u{00A0}for tests",
32345        ] {
32346            is_chart_description_shape(s).unwrap_or_else(|e| {
32347                panic!(
32348                    "non-line-break Unicode chart description {s:?} must pass without rejection: \
32349                     {e:?}"
32350                )
32351            });
32352        }
32353    }
32354
32355    #[test]
32356    fn chart_description_shape_rejects_each_unicode_invisible_format_codepoint() {
32357        // The Unicode invisible-format arm — pins each of the eight
32358        // BMP Cf-category zero-width codepoints with no visible glyph
32359        // in any conforming font. The per-byte non-ASCII pass
32360        // deliberately admits multi-byte UTF-8 sequences (Unicode
32361        // letters / arrows / em-dash are canonical fixtures); only the
32362        // typed codepoint scan catches these eight. Each case carries
32363        // an alphabet-valid prefix + suffix so only the invisible-
32364        // format arm fires. A future drop of any one arm here surfaces
32365        // as a `must be rejected` panic at this one place rather than
32366        // as a silent regression through invisible-codepoint-homograph
32367        // downstream consumers (Artifact Hub description-search
32368        // misses, byte-level diff / grep / equality disagreement with
32369        // the visible-glyph match). Peer of
32370        // `chart_maintainer_name_shape_rejects_each_unicode_invisible_format_codepoint`
32371        // on the sibling predicate — both predicates route through the
32372        // same lifted `find_unicode_invisible_format` helper. Covers
32373        // the four paste-from-Word / paste-from-BOM-editor / paste-
32374        // from-typesetting shapes (U+00AD / U+200B / U+2060 / U+FEFF)
32375        // and the four math-formula invisible operators (U+2061
32376        // FUNCTION APPLICATION / U+2062 INVISIBLE TIMES / U+2063
32377        // INVISIBLE SEPARATOR / U+2064 INVISIBLE PLUS — the canonical
32378        // paste-from-MathJax / paste-from-LaTeX-rendered-formula
32379        // footgun where the renderer emits an invisible operator
32380        // between adjacent symbols for screen-reader operator
32381        // semantics).
32382        for (cp, name) in [
32383            ('\u{00AD}', "U+00AD"),
32384            ('\u{200B}', "U+200B"),
32385            ('\u{2060}', "U+2060"),
32386            ('\u{2061}', "U+2061"),
32387            ('\u{2062}', "U+2062"),
32388            ('\u{2063}', "U+2063"),
32389            ('\u{2064}', "U+2064"),
32390            ('\u{FEFF}', "U+FEFF"),
32391        ] {
32392            let s = format!("Canonical{cp}Servico");
32393            let err = is_chart_description_shape(&s)
32394                .err()
32395                .unwrap_or_else(|| panic!("chart description with {name} must be rejected"));
32396            assert!(
32397                err.contains(name),
32398                "chart description reason for {name} must name the codepoint verbatim; got {err:?}"
32399            );
32400            assert!(
32401                err.contains("invisible-format")
32402                    || err.contains("Cf-category")
32403                    || err.contains("zero-width"),
32404                "chart description reason for {name} must name the invisible-format banner; \
32405                 got {err:?}"
32406            );
32407        }
32408    }
32409
32410    #[test]
32411    fn chart_description_shape_accepts_non_invisible_format_unicode() {
32412        // Positive control on the invisible-format arm: the predicate
32413        // must accept every non-invisible-format Unicode shape canonical
32414        // fixtures carry — including U+200C ZWNJ / U+200D ZWJ
32415        // (legitimate compositional load in Indic / Persian scripts and
32416        // emoji ZWJ sequences) and U+200E LRM / U+200F RLM (legitimate
32417        // single-character direction hints in mixed-script prose). A
32418        // future helper widening that accidentally rejects any of these
32419        // would regress legitimate fixture shapes and surfaces here as
32420        // a single-source-of-truth pin. Mirrors
32421        // `chart_maintainer_name_shape_accepts_non_invisible_format_unicode`
32422        // on the sibling predicate.
32423        for s in [
32424            "Canonical Rust→wasm32-wasip2 caixa Servico.",
32425            "FIXME — describe this caixa",
32426            // Emoji ZWJ sequence (U+200D) — must NOT be rejected: the
32427            // canonical multi-codepoint emoji authoring shape every
32428            // chart-aware UI renders as a single glyph.
32429            "Caixa for the 👨\u{200D}💻 family",
32430            // ZWNJ (U+200C) — legitimate Persian / Indic script
32431            // composition; the helper must NOT claim it.
32432            "Caixa for می\u{200C}باشد",
32433            // Bidi marks LRM (U+200E) and RLM (U+200F) — legitimate
32434            // single-character direction hints, separate class from
32435            // the bidi *overrides* the prior helper rejects.
32436            "Caixa for ASCII\u{200E}embedded in RTL",
32437            "Caixa for \u{200F}RTL hint",
32438        ] {
32439            is_chart_description_shape(s).unwrap_or_else(|e| {
32440                panic!(
32441                    "non-invisible-format Unicode chart description {s:?} must pass without \
32442                     rejection: {e:?}"
32443                )
32444            });
32445        }
32446    }
32447
32448    // ── is_chart_maintainer_name_shape — shared `:autores` chart-maintainer predicate ──
32449
32450    #[test]
32451    fn chart_maintainer_name_shape_accepts_canonical_forms() {
32452        // Substrate-side pin: the predicate accepts every canonical
32453        // chart-maintainer-name shape the `:autores` axis carries.
32454        // Drift between this list and the per-axis
32455        // `manifest::tests::validate_autores_accepts_canonical_forms`
32456        // positive-set sweep surfaces here — one source of truth for
32457        // the rule. Covers the hello-rio / checkout-aplicacao
32458        // `:autores ("pleme-io")` fixture, the multi-author
32459        // `"Pleme Contributors"` shape, and the canonical Helm
32460        // `"name <email>"` shape downstream packaging surfaces emit.
32461        for s in [
32462            "pleme-io",
32463            "Pleme Contributors",
32464            "alice <alice@example.com>",
32465            "bob <bob@example.com>",
32466            "Acme Corporation",
32467            "x",
32468        ] {
32469            is_chart_maintainer_name_shape(s).unwrap_or_else(|e| {
32470                panic!("canonical chart maintainer name {s:?} must pass: {e:?}")
32471            });
32472        }
32473    }
32474
32475    #[test]
32476    fn chart_maintainer_name_shape_rejects_each_arm_with_substring_pinned_reason() {
32477        // Substrate-side diagnostic-shape pin: each arm surfaces its
32478        // own distinct reason substring. Pinned here so a future
32479        // reason-wording rephrase that drops any of these substrings
32480        // surfaces at this one place, not piecemeal across every
32481        // per-axis test sweep. Mirrors
32482        // `chart_description_shape_rejects_each_arm_with_substring_pinned_reason`
32483        // on the peer predicate.
32484        for (s, needle) in [
32485            // Leading whitespace — paste-from-aligned-doc.
32486            (" pleme-io", "whitespace"),
32487            // Trailing whitespace — paste-from-doc.
32488            ("pleme-io ", "whitespace"),
32489            // Tab inside — tab-from-aligned-doc.
32490            ("Pleme\tContributors", "tab"),
32491            // Newline — paste-from-multiline-doc (author pasted
32492            // multi-line author block into one entry).
32493            ("alice\nbob", "newline"),
32494            // Carriage return — paste-from-Windows-CRLF-doc.
32495            ("alice\rbob", "carriage return"),
32496            // NUL byte — paste-from-binary-blob.
32497            ("alice\x00bob", "control character"),
32498            // BEL byte — paste-from-binary-blob.
32499            ("alice\x07bob", "control character"),
32500            // ESC byte — paste-from-binary-blob.
32501            ("alice\x1bbob", "control character"),
32502            // DEL byte (0x7F).
32503            ("alice\x7fbob", "control character"),
32504        ] {
32505            let err = is_chart_maintainer_name_shape(s)
32506                .err()
32507                .unwrap_or_else(|| panic!("chart maintainer name {s:?} must be rejected"));
32508            assert!(
32509                err.contains(needle),
32510                "chart maintainer name {s:?} reason must contain {needle:?}; got {err:?}"
32511            );
32512        }
32513    }
32514
32515    #[test]
32516    fn chart_maintainer_name_shape_accepts_unicode() {
32517        // Positive control on the non-ASCII arm: the predicate must
32518        // accept Unicode beyond the ASCII alphabet — realistic
32519        // maintainer names carry Unicode (`François`, `日本語`,
32520        // `naïve`), and every downstream consumer (YAML 1.2, Helm v3,
32521        // every chart-aware UI) round-trips Unicode losslessly. A
32522        // future tightening that bans non-ASCII bytes would regress
32523        // every Unicode-named maintainer and surface here as a
32524        // regression. Mirrors the peer
32525        // `chart_description_shape_accepts_unicode`.
32526        for s in [
32527            "François Dupont",
32528            "日本語の名前",
32529            "naïve <naive@example.com>",
32530            "André",
32531        ] {
32532            is_chart_maintainer_name_shape(s)
32533                .unwrap_or_else(|e| panic!("Unicode chart maintainer name {s:?} must pass: {e:?}"));
32534        }
32535    }
32536
32537    #[test]
32538    fn chart_maintainer_name_shape_rejects_empty_defensively() {
32539        // The predicate is called from `crate::Caixa::validate_autores`
32540        // only after the per-axis `AutorEmpty` arm has fired at
32541        // validate time; re-checking here keeps the predicate usable
32542        // from any future call site without an empty-precondition
32543        // footgun. Same defensive empty-check `is_dns_1123_label`,
32544        // `is_gateway_api_http_path`, `is_wit_world_ref`,
32545        // `is_nats_subject`, `is_wasi_keyvalue_slot`,
32546        // `is_git_ref_name`, `is_git_oid`, `is_git_repo_url`,
32547        // `is_cargo_feature_name`, `is_spdx_expression_shape`, and
32548        // `is_chart_description_shape` carry at their call sites.
32549        let err = is_chart_maintainer_name_shape("").unwrap_err();
32550        assert!(err.contains("empty"), "got: {err:?}");
32551    }
32552
32553    #[test]
32554    fn chart_maintainer_name_shape_rejects_at_129_byte_boundary() {
32555        // The 128-byte cap pin — both the boundary-exceeding case and
32556        // the boundary-accepting case in one place, so a future cap
32557        // shift surfaces both arms simultaneously, mirroring the peer
32558        // cap-boundary pins (`chart_description_shape_rejects_at_513_byte_boundary`
32559        // on the 512-byte sibling, `spdx_expression_shape_rejects_at_257_byte_boundary`
32560        // on the 256-byte sibling). Constructed as a single all-`a`
32561        // token so only the cap arm fires (128 `a` bytes is
32562        // alphabet-valid).
32563        let max_ok = "a".repeat(CHART_MAINTAINER_NAME_MAX_LEN);
32564        assert_eq!(max_ok.len(), 128);
32565        is_chart_maintainer_name_shape(&max_ok).unwrap();
32566        let too_long = "a".repeat(CHART_MAINTAINER_NAME_MAX_LEN + 1);
32567        assert_eq!(too_long.len(), 129);
32568        let err = is_chart_maintainer_name_shape(&too_long).unwrap_err();
32569        assert!(err.contains("128"), "got: {err:?}");
32570        assert!(err.contains("129"), "got: {err:?}");
32571    }
32572
32573    #[test]
32574    fn chart_maintainer_name_shape_rejects_each_unicode_bidi_override_codepoint() {
32575        // The Trojan Source (CVE-2021-42574) arm — pins every UAX #9
32576        // bidirectional-override / isolate format codepoint as a
32577        // structural rejection on the typed `:autores` axis. Mirrors
32578        // `chart_description_shape_rejects_each_unicode_bidi_override_codepoint`
32579        // on the peer predicate — both predicates route through the
32580        // same lifted `find_unicode_bidi_override` helper, so dropping
32581        // any one of the nine arms from the helper's match would
32582        // regress both peer test sweeps simultaneously at this one
32583        // structural floor rather than at piecemeal per-axis call
32584        // sites. The canonical attacker shape: an `:autores
32585        // "alice\u{202E}example.com<bob@"` entry renders in `helm
32586        // list`'s maintainer column / Artifact Hub as the visually-
32587        // reversed `alice<@bob>moc.elpmaxe` while riding verbatim
32588        // into the Chart.yaml `maintainers:` array — exactly the
32589        // class this arm closes.
32590        for (cp, name) in [
32591            ('\u{202A}', "U+202A"),
32592            ('\u{202B}', "U+202B"),
32593            ('\u{202C}', "U+202C"),
32594            ('\u{202D}', "U+202D"),
32595            ('\u{202E}', "U+202E"),
32596            ('\u{2066}', "U+2066"),
32597            ('\u{2067}', "U+2067"),
32598            ('\u{2068}', "U+2068"),
32599            ('\u{2069}', "U+2069"),
32600        ] {
32601            let s = format!("alice{cp}bob");
32602            let err = is_chart_maintainer_name_shape(&s)
32603                .err()
32604                .unwrap_or_else(|| panic!("chart maintainer name with {name} must be rejected"));
32605            assert!(
32606                err.contains(name),
32607                "chart maintainer name reason for {name} must name the codepoint verbatim; \
32608                 got {err:?}"
32609            );
32610            assert!(
32611                err.contains("bidirectional-override")
32612                    || err.contains("Unicode bidi")
32613                    || err.contains("Trojan Source"),
32614                "chart maintainer name reason for {name} must name the Trojan-Source banner; \
32615                 got {err:?}"
32616            );
32617        }
32618    }
32619
32620    #[test]
32621    fn chart_maintainer_name_shape_accepts_pure_rtl_text_without_bidi_override() {
32622        // Positive control on the bidi-override arm: pure visual
32623        // right-to-left scripts (Hebrew, Arabic) decode to non-bidi-
32624        // override codepoints and the predicate must accept them
32625        // natively — banning all RTL would regress every Hebrew /
32626        // Arabic-authored maintainer-name entry, which the substrate
32627        // supports via the non-ASCII byte arm. Peer of
32628        // `chart_description_shape_accepts_pure_rtl_text_without_bidi_override`
32629        // on the sibling YAML-plain-style-scalar surface.
32630        for s in [
32631            // Pure Hebrew maintainer name.
32632            "שלום",
32633            // Pure Arabic maintainer name.
32634            "مرحبا",
32635            // Mixed-script — canonical multilingual maintainer
32636            // shape every YAML 1.2 + Helm v3 round-trips losslessly.
32637            "Acme שלום",
32638        ] {
32639            is_chart_maintainer_name_shape(s).unwrap_or_else(|e| {
32640                panic!(
32641                    "pure-RTL chart maintainer name {s:?} must pass without bidi override: {e:?}"
32642                )
32643            });
32644        }
32645    }
32646
32647    #[test]
32648    fn chart_maintainer_name_shape_rejects_each_unicode_line_break_codepoint() {
32649        // The non-ASCII Unicode line-break arm — pins each of the three
32650        // UAX #14 / YAML 1.1 §4.1 line-break codepoints outside the
32651        // ASCII `\n` / `\r` bytes already caught at the per-byte pass.
32652        // The canonical YAML-1.1-vs-YAML-1.2 paste-from-doc footgun: an
32653        // `:autores "alice\u{2028}bob"` entry parses as one
32654        // `maintainers:` array entry through a YAML 1.2-strict parser
32655        // and as two entries through a YAML 1.1 parser (go-yaml v2 /
32656        // Helm v3). Mirrors
32657        // `chart_description_shape_rejects_each_unicode_line_break_codepoint`
32658        // on the peer predicate — both predicates route through the
32659        // same lifted `find_unicode_line_break` helper, so dropping
32660        // any one of the three arms from the helper's match would
32661        // regress both peer test sweeps simultaneously at this one
32662        // structural floor.
32663        for (cp, name) in [
32664            ('\u{0085}', "U+0085"),
32665            ('\u{2028}', "U+2028"),
32666            ('\u{2029}', "U+2029"),
32667        ] {
32668            let s = format!("alice{cp}bob");
32669            let err = is_chart_maintainer_name_shape(&s)
32670                .err()
32671                .unwrap_or_else(|| panic!("chart maintainer name with {name} must be rejected"));
32672            assert!(
32673                err.contains(name),
32674                "chart maintainer name reason for {name} must name the codepoint verbatim; \
32675                 got {err:?}"
32676            );
32677            assert!(
32678                err.contains("line-break") || err.contains("UAX #14") || err.contains("YAML 1.1"),
32679                "chart maintainer name reason for {name} must name the Unicode-line-break banner; \
32680                 got {err:?}"
32681            );
32682        }
32683    }
32684
32685    #[test]
32686    fn chart_maintainer_name_shape_accepts_non_line_break_unicode() {
32687        // Positive control on the line-break arm: the predicate must
32688        // accept every non-line-break Unicode shape canonical
32689        // maintainer names carry. Pinned alongside the per-codepoint
32690        // rejection sweep so a future helper widening that
32691        // accidentally rejects a non-line-break codepoint surfaces
32692        // here as a single-source-of-truth pin. Peer of
32693        // `chart_description_shape_accepts_non_line_break_unicode`
32694        // on the sibling YAML-plain-style-scalar surface.
32695        for s in [
32696            "François Dupont",
32697            "日本語の名前",
32698            "naïve <naive@example.com>",
32699            "André",
32700            // U+00A0 NO-BREAK SPACE is NOT a line-break codepoint
32701            // (UAX #14 class GL — Glue, non-breaking) and is the
32702            // canonical authoring shape for unbreakable space inside
32703            // a multi-token maintainer name — must pass.
32704            "Acme\u{00A0}Corp",
32705        ] {
32706            is_chart_maintainer_name_shape(s).unwrap_or_else(|e| {
32707                panic!(
32708                    "non-line-break Unicode chart maintainer name {s:?} must pass without \
32709                     rejection: {e:?}"
32710                )
32711            });
32712        }
32713    }
32714
32715    #[test]
32716    fn chart_maintainer_name_shape_rejects_each_unicode_invisible_format_codepoint() {
32717        // The Unicode invisible-format arm — pins each of the eight
32718        // BMP Cf-category zero-width codepoints with no visible glyph.
32719        // The canonical maintainer-identity homograph footgun: an
32720        // `:autores "alice\u{200B}"` entry renders identically to
32721        // `:autores "alice"` in `helm list` / Artifact Hub's
32722        // maintainer column, but the byte sequence is distinct — the
32723        // Artifact Hub maintainer-index lookup misses the authored
32724        // `"alice"` entry, a future CLA-signer lookup matches a
32725        // visually-identical-but-byte-distinct identity. Mirrors
32726        // `chart_description_shape_rejects_each_unicode_invisible_format_codepoint`
32727        // on the peer predicate — both predicates route through the
32728        // same lifted `find_unicode_invisible_format` helper, so
32729        // dropping any one of the eight arms from the helper's match
32730        // would regress both peer test sweeps simultaneously at this
32731        // one structural floor. Covers the four paste-from-Word /
32732        // paste-from-BOM-editor / paste-from-typesetting shapes
32733        // (U+00AD / U+200B / U+2060 / U+FEFF) and the four math-
32734        // formula invisible operators (U+2061 FUNCTION APPLICATION /
32735        // U+2062 INVISIBLE TIMES / U+2063 INVISIBLE SEPARATOR /
32736        // U+2064 INVISIBLE PLUS — paste-from-MathJax / paste-from-
32737        // LaTeX-rendered-formula footgun).
32738        for (cp, name) in [
32739            ('\u{00AD}', "U+00AD"),
32740            ('\u{200B}', "U+200B"),
32741            ('\u{2060}', "U+2060"),
32742            ('\u{2061}', "U+2061"),
32743            ('\u{2062}', "U+2062"),
32744            ('\u{2063}', "U+2063"),
32745            ('\u{2064}', "U+2064"),
32746            ('\u{FEFF}', "U+FEFF"),
32747        ] {
32748            let s = format!("alice{cp}bob");
32749            let err = is_chart_maintainer_name_shape(&s)
32750                .err()
32751                .unwrap_or_else(|| panic!("chart maintainer name with {name} must be rejected"));
32752            assert!(
32753                err.contains(name),
32754                "chart maintainer name reason for {name} must name the codepoint verbatim; \
32755                 got {err:?}"
32756            );
32757            assert!(
32758                err.contains("invisible-format")
32759                    || err.contains("Cf-category")
32760                    || err.contains("zero-width"),
32761                "chart maintainer name reason for {name} must name the invisible-format banner; \
32762                 got {err:?}"
32763            );
32764        }
32765    }
32766
32767    #[test]
32768    fn chart_maintainer_name_shape_accepts_non_invisible_format_unicode() {
32769        // Positive control on the invisible-format arm: the predicate
32770        // must accept the legitimate-use codepoints the helper
32771        // deliberately excludes — U+200C ZWNJ / U+200D ZWJ (emoji ZWJ
32772        // sequences are canonical for modern maintainer-display names;
32773        // Indic / Persian script composition relies on ZWNJ to break
32774        // inappropriate ligatures) and U+200E LRM / U+200F RLM
32775        // (mixed-script direction hints are canonical for "Arabic name
32776        // with embedded ASCII email" shapes). Peer of
32777        // `chart_description_shape_accepts_non_invisible_format_unicode`
32778        // on the sibling YAML-plain-style-scalar surface.
32779        for s in [
32780            "François Dupont",
32781            "naïve <naive@example.com>",
32782            // Emoji ZWJ sequence (U+200D) — canonical multi-codepoint
32783            // emoji authoring shape.
32784            "Joe 👨\u{200D}💻 Developer",
32785            // ZWNJ (U+200C) — legitimate Persian / Indic composition.
32786            "Persian می\u{200C}باشد maintainer",
32787            // Bidi marks LRM / RLM — legitimate direction hints in
32788            // mixed-script maintainer names.
32789            "Arabic\u{200F}name <maintainer@example.com>",
32790            "ASCII\u{200E}embedded in RTL context",
32791        ] {
32792            is_chart_maintainer_name_shape(s).unwrap_or_else(|e| {
32793                panic!(
32794                    "non-invisible-format Unicode chart maintainer name {s:?} must pass without \
32795                     rejection: {e:?}"
32796                )
32797            });
32798        }
32799    }
32800
32801    #[test]
32802    fn find_unicode_bidi_override_pins_the_nine_codepoint_accepted_set() {
32803        // The shared helper's accepted set — pinned in one place so
32804        // every per-predicate caller (`is_chart_description_shape`,
32805        // `is_chart_maintainer_name_shape`, every future free-form-
32806        // prose surface) reads from one canonical accepted set. The
32807        // nine UAX #9 bidirectional-override / isolate format
32808        // codepoints in document order, plus negative controls on
32809        // bytes the helper must NOT reject (ASCII / non-bidi Unicode
32810        // letters / arrows / em-dash / RTL letters). A future shift
32811        // in the accepted set surfaces here as a single-source-of-
32812        // truth edit at this one test rather than across every
32813        // per-predicate per-arm sweep.
32814        for cp in [
32815            '\u{202A}', '\u{202B}', '\u{202C}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}',
32816            '\u{2068}', '\u{2069}',
32817        ] {
32818            let s = format!("a{cp}b");
32819            assert_eq!(
32820                find_unicode_bidi_override(&s),
32821                Some(cp),
32822                "helper must flag bidi override U+{:04X} on input {s:?}",
32823                cp as u32
32824            );
32825        }
32826        for s in [
32827            "alice",
32828            "Canonical Rust→wasm32-wasip2",
32829            "FIXME — describe this caixa",
32830            "François Dupont",
32831            "日本語の説明",
32832            "naïve",
32833            "שלום",
32834            "مرحبا",
32835        ] {
32836            assert_eq!(
32837                find_unicode_bidi_override(s),
32838                None,
32839                "helper must accept {s:?} (no bidi-override codepoint)"
32840            );
32841        }
32842        // Empty input — defensive precondition for the helper's
32843        // call-site contract on any future caller that doesn't gate
32844        // emptiness ahead of the scan.
32845        assert_eq!(find_unicode_bidi_override(""), None);
32846    }
32847
32848    #[test]
32849    fn find_unicode_line_break_pins_the_three_codepoint_accepted_set() {
32850        // The shared helper's accepted set — pinned in one place so
32851        // every per-predicate caller (`is_chart_description_shape`,
32852        // `is_chart_maintainer_name_shape`, every future free-form-
32853        // prose surface) reads from one canonical accepted set. The
32854        // three UAX #14 / YAML 1.1 §4.1 non-ASCII line-break
32855        // codepoints in document order, plus negative controls on
32856        // bytes the helper must NOT reject (ASCII text, Unicode
32857        // letters / arrows / em-dash / RTL letters, the canonical
32858        // non-line-break U+00A0 NBSP shape downstream YAML 1.2 +
32859        // Helm v3 + every chart-aware UI round-trip losslessly). A
32860        // future shift in the accepted set surfaces here as a
32861        // single-source-of-truth edit at this one test rather than
32862        // across every per-predicate per-arm sweep. Peer of
32863        // `find_unicode_bidi_override_pins_the_nine_codepoint_accepted_set`
32864        // on the sibling lifted-helper one trajectory earlier.
32865        for cp in ['\u{0085}', '\u{2028}', '\u{2029}'] {
32866            let s = format!("a{cp}b");
32867            assert_eq!(
32868                find_unicode_line_break(&s),
32869                Some(cp),
32870                "helper must flag line-break codepoint U+{:04X} on input {s:?}",
32871                cp as u32
32872            );
32873        }
32874        for s in [
32875            "alice",
32876            "Canonical Rust→wasm32-wasip2",
32877            "FIXME — describe this caixa",
32878            "François Dupont",
32879            "日本語の説明",
32880            "naïve",
32881            "שלום",
32882            "مرحبا",
32883            // U+00A0 NO-BREAK SPACE — UAX #14 class GL (Glue,
32884            // non-breaking) — must NOT be rejected: the canonical
32885            // unbreakable-space shape every typed maintainer-name
32886            // axis admits.
32887            "Acme\u{00A0}Corp",
32888            // U+0009 TAB and U+000A LF and U+000D CR — ASCII
32889            // line-break / whitespace bytes the per-byte arm on the
32890            // calling predicate already closes; the helper must NOT
32891            // claim them as its own (single-source-of-truth: ASCII
32892            // arms live in the per-byte loop, the helper closes the
32893            // non-ASCII codepoints).
32894            "alice\tbob",
32895            "alice\nbob",
32896            "alice\rbob",
32897        ] {
32898            assert_eq!(
32899                find_unicode_line_break(s),
32900                None,
32901                "helper must accept {s:?} (no non-ASCII line-break codepoint)"
32902            );
32903        }
32904        // Empty input — defensive precondition for the helper's
32905        // call-site contract on any future caller that doesn't gate
32906        // emptiness ahead of the scan.
32907        assert_eq!(find_unicode_line_break(""), None);
32908    }
32909
32910    #[test]
32911    fn find_unicode_invisible_format_pins_the_eight_codepoint_accepted_set() {
32912        // The shared helper's accepted set — pinned in one place so
32913        // every per-predicate caller (`is_chart_description_shape`,
32914        // `is_chart_maintainer_name_shape`, every future free-form-
32915        // prose surface) reads from one canonical accepted set. The
32916        // eight BMP Cf-category zero-width codepoints in document
32917        // order — the four paste-from-Word / paste-from-BOM-editor /
32918        // paste-from-typesetting-doc shapes (U+00AD SHY / U+200B ZWSP /
32919        // U+2060 WJ / U+FEFF ZWNBSP-BOM) and the four math-formula
32920        // invisible operators (U+2061 FUNCTION APPLICATION / U+2062
32921        // INVISIBLE TIMES / U+2063 INVISIBLE SEPARATOR / U+2064
32922        // INVISIBLE PLUS — paste-from-MathJax / paste-from-LaTeX-
32923        // rendered-formula / paste-from-InDesign-math-equation
32924        // shapes) — plus negative controls on codepoints the helper
32925        // must NOT reject — the deliberate exclusions: U+200C ZWNJ /
32926        // U+200D ZWJ (emoji ZWJ sequences + Indic / Persian script
32927        // composition) and U+200E LRM / U+200F RLM (mixed-script
32928        // direction hints). A future shift in the accepted set
32929        // surfaces here as a single-source-of-truth edit at this one
32930        // test rather than across every per-predicate per-arm sweep.
32931        // Third pin in the UAX-driven render-determinism trio (peer of
32932        // `find_unicode_bidi_override_pins_the_nine_codepoint_accepted_set`
32933        // on the visual-order axis and
32934        // `find_unicode_line_break_pins_the_three_codepoint_accepted_set`
32935        // on the single-line/multi-line axis).
32936        for cp in [
32937            '\u{00AD}', '\u{200B}', '\u{2060}', '\u{2061}', '\u{2062}', '\u{2063}', '\u{2064}',
32938            '\u{FEFF}',
32939        ] {
32940            let s = format!("a{cp}b");
32941            assert_eq!(
32942                find_unicode_invisible_format(&s),
32943                Some(cp),
32944                "helper must flag invisible-format codepoint U+{:04X} on input {s:?}",
32945                cp as u32
32946            );
32947        }
32948        for s in [
32949            "alice",
32950            "Canonical Rust→wasm32-wasip2",
32951            "FIXME — describe this caixa",
32952            "François Dupont",
32953            "日本語の説明",
32954            "naïve",
32955            "שלום",
32956            "مرحبا",
32957            // U+00A0 NO-BREAK SPACE — class GL (Glue), visible-width
32958            // codepoint — must NOT be claimed by the invisible-format
32959            // helper (the canonical unbreakable-space shape).
32960            "Acme\u{00A0}Corp",
32961            // U+200C ZWNJ — deliberately excluded (Indic / Persian
32962            // composition + emoji ZWJ-adjacent context).
32963            "می\u{200C}باشد",
32964            // U+200D ZWJ — deliberately excluded (emoji ZWJ
32965            // sequences are canonical: 👨‍💻 is MAN + ZWJ + LAPTOP).
32966            "Joe 👨\u{200D}💻 Developer",
32967            // U+200E LRM — deliberately excluded (direction-hint
32968            // mark, not a direction-override; legitimate in
32969            // mixed-script prose).
32970            "ASCII\u{200E}embedded",
32971            // U+200F RLM — deliberately excluded (mirror of LRM
32972            // on the RTL axis).
32973            "Arabic\u{200F}name",
32974            // Bidi-override codepoints (U+202A..U+202E, U+2066..U+2069)
32975            // — caught by the sibling `find_unicode_bidi_override`
32976            // helper, not this one (single-source-of-truth: each
32977            // helper closes exactly its class).
32978            "alice\u{202E}bob",
32979            // Line-break codepoints (U+0085, U+2028, U+2029) — caught
32980            // by the sibling `find_unicode_line_break` helper.
32981            "alice\u{2028}bob",
32982        ] {
32983            assert_eq!(
32984                find_unicode_invisible_format(s),
32985                None,
32986                "helper must accept {s:?} (no invisible-format codepoint in the four-codepoint set)"
32987            );
32988        }
32989        // Empty input — defensive precondition for the helper's
32990        // call-site contract on any future caller that doesn't gate
32991        // emptiness ahead of the scan.
32992        assert_eq!(find_unicode_invisible_format(""), None);
32993    }
32994
32995    // ── is_chart_keyword_shape — shared `:etiquetas` chart-keyword predicate ──
32996
32997    #[test]
32998    fn chart_keyword_shape_accepts_canonical_forms() {
32999        // Substrate-side pin: the predicate accepts every canonical
33000        // chart-keyword shape the `:etiquetas` axis carries. Drift
33001        // between this list and the per-axis
33002        // `manifest::tests::validate_etiquetas_accepts_canonical_shaped_forms`
33003        // positive-set sweep surfaces here — one source of truth for
33004        // the rule. Covers the example fixtures'
33005        // `:etiquetas` lists (`"example"`, `"aplicacao"`, `"mesh"`,
33006        // `"ecommerce"`, `"demo"`, `"infrastructure"`, `"aws"`,
33007        // `"akeyless"`, `"pangea-native"`) and the substrate-fixed
33008        // tags caixa-helm unions in at chart render (`"lareira"`,
33009        // `"wasm"`, `"tatara-lisp"`, `"caixa-servico"`).
33010        let example_fixture_tags = [
33011            "example",
33012            "aplicacao",
33013            "mesh",
33014            "ecommerce",
33015            "demo",
33016            "infrastructure",
33017            "aws",
33018            "akeyless",
33019            "pangea-native",
33020            "hello-world",
33021            "rust",
33022            "Foo",
33023            "Bar123",
33024            "x",
33025            "snake_case_tag",
33026        ];
33027        for s in example_fixture_tags
33028            .iter()
33029            .copied()
33030            .chain(LAREIRA_CHART_KEYWORDS.iter().copied())
33031        {
33032            is_chart_keyword_shape(s)
33033                .unwrap_or_else(|e| panic!("canonical chart keyword {s:?} must pass: {e:?}"));
33034        }
33035    }
33036
33037    #[test]
33038    fn lareira_chart_keywords_pins_canonical_ordered_set() {
33039        // Substrate-side canonical-set pin: byte-pins the
33040        // substrate-fixed `Chart.yaml` `keywords:` union caixa-helm's
33041        // `build_chart_yaml` folds into every rendered `lareira-<nome>`
33042        // chart on top of the caixa author's own `:etiquetas`. The
33043        // ordered array shape (`BTreeSet`-canonical ascii-alphabetical)
33044        // pins the same order the emitted `Chart.yaml` `keywords:`
33045        // sequence lists them after the intermediate
33046        // `BTreeSet<String>` fold at the caixa-helm emit site. A drift
33047        // between the canonical array and either the production emit
33048        // at `caixa-helm::build_chart_yaml` (the sole consumer) or
33049        // the peer positive-set sweep tests (this crate's
33050        // `chart_keyword_shape_accepts_canonical_forms` and
33051        // `manifest::tests::validate_etiquetas_accepts_canonical_shaped_forms`)
33052        // surfaces at this one substrate-side pin.
33053        assert_eq!(
33054            LAREIRA_CHART_KEYWORDS,
33055            &["caixa-servico", "lareira", "tatara-lisp", "wasm"],
33056        );
33057    }
33058
33059    #[test]
33060    fn lareira_chart_keywords_stays_btreeset_canonical_ordered() {
33061        // Substrate-side ordering pin: the array is
33062        // `BTreeSet`-canonical ascii-alphabetical, so its declared
33063        // order matches the shape the emitted `Chart.yaml`
33064        // `keywords:` sequence carries after
33065        // `caixa-helm::build_chart_yaml`'s intermediate
33066        // `BTreeSet<String>` fold — a future substrate-fixed keyword
33067        // addition that lands out-of-order (an `"opentelemetry"` entry
33068        // dropped before `"tatara-lisp"`, an `"lunatic"` entry dropped
33069        // after `"wasm"`) trips this pin at caixa-core build time
33070        // rather than surfacing as a byte-shape drift between the
33071        // array's declared order and the emitted `keywords:` sequence
33072        // order at chart render time downstream.
33073        let mut sorted: Vec<&str> = LAREIRA_CHART_KEYWORDS.to_vec();
33074        sorted.sort_unstable();
33075        assert_eq!(LAREIRA_CHART_KEYWORDS, sorted.as_slice());
33076    }
33077
33078    #[test]
33079    fn lareira_chart_keywords_each_entry_passes_is_chart_keyword_shape() {
33080        // Substrate-side shape-invariant pin: every substrate-fixed
33081        // chart-keyword entry must satisfy the per-`Chart.yaml`
33082        // `keywords:` entry validation predicate the substrate
33083        // enforces on the author-side `:etiquetas` axis — a future
33084        // substrate-fixed keyword addition that happens to break the
33085        // shape rule (a leading digit, an uppercase letter, a byte
33086        // over the `CHART_KEYWORD_MAX_LEN` cap, an ASCII whitespace,
33087        // a Unicode-invisible-format code point) trips this pin at
33088        // caixa-core build time rather than surfacing at
33089        // `helm lint` time on the rendered chart downstream.
33090        for keyword in LAREIRA_CHART_KEYWORDS {
33091            is_chart_keyword_shape(keyword).unwrap_or_else(|e| {
33092                panic!(
33093                    "substrate-fixed chart keyword {keyword:?} must pass \
33094                     is_chart_keyword_shape: {e:?}"
33095                )
33096            });
33097        }
33098    }
33099
33100    #[test]
33101    fn chart_keyword_shape_rejects_each_arm_with_substring_pinned_reason() {
33102        // Substrate-side diagnostic-shape pin: each arm surfaces its
33103        // own distinct reason substring. Pinned here so a future
33104        // reason-wording rephrase that drops any of these substrings
33105        // surfaces at this one place, not piecemeal across every
33106        // per-axis test sweep. Mirrors
33107        // `chart_maintainer_name_shape_rejects_each_arm_with_substring_pinned_reason`
33108        // on the peer predicate.
33109        for (s, needle) in [
33110            // Leading whitespace — paste-from-aligned-doc.
33111            (" mesh", "whitespace"),
33112            // Leading hyphen — kebab-leak footgun.
33113            ("-foo", "`-`"),
33114            // Leading underscore — snake-leak footgun.
33115            ("_foo", "`_`"),
33116            // Leading digit — paste-from-numbered-list footgun.
33117            ("1foo", "digit"),
33118            // Embedded whitespace — multi-tag-blob footgun.
33119            ("web service", "whitespace"),
33120            // Tab inside — tab-from-aligned-doc.
33121            ("mesh\thttp", "whitespace"),
33122            // Newline — paste-from-multiline-doc.
33123            ("mesh\nhttp", "newline"),
33124            // Carriage return — paste-from-Windows-CRLF-doc.
33125            ("mesh\rhttp", "carriage return"),
33126            // Comma — CSV-list-separator confusion.
33127            ("mesh,http", "`,`"),
33128            // Slash — path-separator confusion.
33129            ("caixa/servico", "`/`"),
33130            // Semicolon — alt-list-separator confusion.
33131            ("mesh;http", "`;`"),
33132            // Period — namespace / version-suffix confusion.
33133            ("http.1", "`.`"),
33134            // NUL byte — paste-from-binary-blob.
33135            ("mesh\x00http", "control character"),
33136            // DEL byte (0x7F).
33137            ("mesh\x7fhttp", "control character"),
33138            // Non-ASCII inside.
33139            ("café", "non-ASCII"),
33140            // Non-ASCII leading.
33141            ("éclair", "non-ASCII"),
33142        ] {
33143            let err = is_chart_keyword_shape(s)
33144                .err()
33145                .unwrap_or_else(|| panic!("chart keyword {s:?} must be rejected"));
33146            assert!(
33147                err.contains(needle),
33148                "chart keyword {s:?} reason must contain {needle:?}; got {err:?}"
33149            );
33150        }
33151    }
33152
33153    #[test]
33154    fn chart_keyword_shape_rejects_empty_defensively() {
33155        // The predicate is called from `crate::Caixa::validate_etiquetas`
33156        // only after the per-axis `EtiquetaEmpty` arm has fired at
33157        // validate time; re-checking here keeps the predicate usable
33158        // from any future call site without an empty-precondition
33159        // footgun. Same defensive empty-check `is_dns_1123_label`,
33160        // `is_gateway_api_http_path`, `is_wit_world_ref`,
33161        // `is_nats_subject`, `is_wasi_keyvalue_slot`,
33162        // `is_git_ref_name`, `is_git_oid`, `is_git_repo_url`,
33163        // `is_cargo_feature_name`, `is_spdx_expression_shape`,
33164        // `is_chart_description_shape`, and
33165        // `is_chart_maintainer_name_shape` carry at their call sites.
33166        let err = is_chart_keyword_shape("").unwrap_err();
33167        assert!(err.contains("empty"), "got: {err:?}");
33168    }
33169
33170    #[test]
33171    fn chart_keyword_shape_rejects_at_21_byte_boundary() {
33172        // The 20-byte cap pin — both the boundary-exceeding case and
33173        // the boundary-accepting case in one place, so a future cap
33174        // shift surfaces both arms simultaneously, mirroring the peer
33175        // cap-boundary pins
33176        // (`chart_maintainer_name_shape_rejects_at_129_byte_boundary`
33177        // on the 128-byte sibling,
33178        // `chart_description_shape_rejects_at_513_byte_boundary` on
33179        // the 512-byte sibling). Constructed as a single all-`a`
33180        // token so only the cap arm fires (20 `a` bytes is alphabet-
33181        // valid).
33182        let max_ok = "a".repeat(CHART_KEYWORD_MAX_LEN);
33183        assert_eq!(max_ok.len(), 20);
33184        is_chart_keyword_shape(&max_ok).unwrap();
33185        let too_long = "a".repeat(CHART_KEYWORD_MAX_LEN + 1);
33186        assert_eq!(too_long.len(), 21);
33187        let err = is_chart_keyword_shape(&too_long).unwrap_err();
33188        assert!(err.contains("20"), "got: {err:?}");
33189        assert!(err.contains("21"), "got: {err:?}");
33190    }
33191
33192    // ── shared predicate: find_ascii_whitespace_byte ──────────────────
33193    //
33194    // Pins the accepted / rejected set of the lifted ASCII byte-scan
33195    // every typed-magnitude codec in caixa-core calls (`parse_byte_size`
33196    // / `parse_duration` / `parse_millicores` / shared
33197    // `duration_codec` / `rate_limit_codec`). Peer of the non-ASCII
33198    // `find_non_ascii_whitespace_char` predicate below — together they
33199    // partition the full Unicode `White_Space` axis.
33200
33201    #[test]
33202    fn find_ascii_whitespace_byte_accepts_whitespace_free_strings() {
33203        // Complement-side pin: every whitespace-free canonical form
33204        // the renderers emit returns `None`.
33205        assert!(find_ascii_whitespace_byte("64MiB").is_none());
33206        assert!(find_ascii_whitespace_byte("30s").is_none());
33207        assert!(find_ascii_whitespace_byte("500m").is_none());
33208        assert!(find_ascii_whitespace_byte("100/s").is_none());
33209        assert!(find_ascii_whitespace_byte("").is_none());
33210        assert!(find_ascii_whitespace_byte("abcdef0123-_").is_none());
33211        // Non-whitespace ASCII bytes near the whitespace range stay
33212        // accepted (the predicate must not over-fire on peer control
33213        // bytes like VT `0x0B` which POSIX admits but WhatWG excludes).
33214        assert!(find_ascii_whitespace_byte("\u{0B}64MiB").is_none());
33215    }
33216
33217    #[test]
33218    fn find_ascii_whitespace_byte_flags_space() {
33219        // Space (`0x20`) — the canonical paste-from-shell-history /
33220        // paste-from-aligned-doc drift class.
33221        assert_eq!(find_ascii_whitespace_byte(" 64MiB"), Some(0x20));
33222        assert_eq!(find_ascii_whitespace_byte("30s "), Some(0x20));
33223        assert_eq!(find_ascii_whitespace_byte("100 /s"), Some(0x20));
33224    }
33225
33226    #[test]
33227    fn find_ascii_whitespace_byte_flags_tab_lf_ff_cr() {
33228        // Tab (`0x09`), LF (`0x0A`), FF (`0x0C`), CR (`0x0D`) —
33229        // the remaining four bytes in the WhatWG ASCII whitespace
33230        // set the predicate covers, verbatim.
33231        assert_eq!(find_ascii_whitespace_byte("\t500m"), Some(0x09));
33232        assert_eq!(find_ascii_whitespace_byte("30s\n"), Some(0x0A));
33233        assert_eq!(find_ascii_whitespace_byte("\x0c64MiB"), Some(0x0C));
33234        assert_eq!(find_ascii_whitespace_byte("100/s\r"), Some(0x0D));
33235    }
33236
33237    #[test]
33238    fn find_ascii_whitespace_byte_returns_first_match_byte_order() {
33239        // The predicate returns the *first* offending byte in scan
33240        // order — pinning this so a self-locating codec diagnostic can
33241        // report "position 0" / "position N" verbatim without the
33242        // predicate ever reordering matches.
33243        assert_eq!(find_ascii_whitespace_byte(" \t30s"), Some(0x20));
33244        assert_eq!(find_ascii_whitespace_byte("\t 30s"), Some(0x09));
33245    }
33246
33247    #[test]
33248    fn find_ascii_whitespace_byte_does_not_flag_non_ascii_whitespace() {
33249        // NBSP (`\u{00A0}`), LINE SEPARATOR (`\u{2028}`), IDEOGRAPHIC
33250        // SPACE (`\u{3000}`) — none of their UTF-8 bytes match
33251        // `u8::is_ascii_whitespace` (NBSP's `0xC2 0xA0`, LINE
33252        // SEPARATOR's `0xE2 0x80 0xA8`, IDEOGRAPHIC SPACE's `0xE3
33253        // 0x80 0x80` all sit above `0x7F` or well outside the
33254        // {`0x09`, `0x0A`, `0x0C`, `0x0D`, `0x20`} set). Pinning this
33255        // exclusion so the peer `find_non_ascii_whitespace_char`
33256        // predicate remains strictly complementary — the two together
33257        // partition the full Unicode `White_Space` axis with zero
33258        // overlap.
33259        assert!(find_ascii_whitespace_byte("\u{00A0}64MiB").is_none());
33260        assert!(find_ascii_whitespace_byte("30s\u{2028}").is_none());
33261        assert!(find_ascii_whitespace_byte("64MiB\u{3000}").is_none());
33262    }
33263
33264    // ── shared predicate: find_non_ascii_whitespace_char ──────────────────
33265    //
33266    // Pins the accepted / rejected set of the lifted predicate every
33267    // typed-magnitude codec in caixa-core calls (byte-size / duration /
33268    // shared duration / rate-limit). The predicate's job is exclusively
33269    // to name the strictly-complementary drift class the peer
33270    // `u8::is_ascii_whitespace` byte-scan cannot see — the non-ASCII
33271    // Unicode `White_Space` subset that `str::trim` silently swallows.
33272
33273    #[test]
33274    fn find_non_ascii_whitespace_char_accepts_ascii_only_strings() {
33275        // Complement-side pin: every ASCII-only string (canonical form
33276        // and ASCII whitespace alike) returns `None`. The predicate is
33277        // strictly complementary to the per-codec ASCII byte-scan; it
33278        // must not shadow its coverage.
33279        assert!(find_non_ascii_whitespace_char("64MiB").is_none());
33280        assert!(find_non_ascii_whitespace_char("30s").is_none());
33281        assert!(find_non_ascii_whitespace_char("100/s").is_none());
33282        assert!(find_non_ascii_whitespace_char(" \t\n").is_none());
33283        assert!(find_non_ascii_whitespace_char("").is_none());
33284        // Non-whitespace ASCII byte peers stay accepted too.
33285        assert!(find_non_ascii_whitespace_char("abcdef0123-_").is_none());
33286    }
33287
33288    #[test]
33289    fn find_non_ascii_whitespace_char_flags_nbsp() {
33290        // `\u{00A0}` NBSP — the canonical paste-from-typography /
33291        // paste-from-word-processor drift class.
33292        assert_eq!(
33293            find_non_ascii_whitespace_char("64\u{00A0}MiB"),
33294            Some('\u{00A0}')
33295        );
33296        assert_eq!(find_non_ascii_whitespace_char("\u{00A0}"), Some('\u{00A0}'));
33297    }
33298
33299    #[test]
33300    fn find_non_ascii_whitespace_char_flags_line_and_paragraph_separators() {
33301        // LINE SEPARATOR (`\u{2028}`) / PARAGRAPH SEPARATOR
33302        // (`\u{2029}`) — the paste-from-web-doc drift class every
33303        // RTF/HTML → plain-text conversion emits at soft-wrap
33304        // boundaries.
33305        assert_eq!(
33306            find_non_ascii_whitespace_char("30s\u{2028}"),
33307            Some('\u{2028}')
33308        );
33309        assert_eq!(
33310            find_non_ascii_whitespace_char("30s\u{2029}"),
33311            Some('\u{2029}')
33312        );
33313    }
33314
33315    #[test]
33316    fn find_non_ascii_whitespace_char_flags_ideographic_space() {
33317        // IDEOGRAPHIC SPACE (`\u{3000}`) — the CJK-typography drift
33318        // class every full-width IME auto-widens ASCII space to on
33319        // Japanese / Chinese input methods.
33320        assert_eq!(
33321            find_non_ascii_whitespace_char("64MiB\u{3000}"),
33322            Some('\u{3000}')
33323        );
33324    }
33325
33326    #[test]
33327    fn find_non_ascii_whitespace_char_does_not_flag_zwsp_or_bom() {
33328        // BOM (`\u{FEFF}`, ZERO WIDTH NO-BREAK SPACE) and ZWSP
33329        // (`\u{200B}`, ZERO WIDTH SPACE) — both have
33330        // `char::is_whitespace() == false` per the Unicode
33331        // `White_Space` property, so `str::trim` does *not* strip
33332        // either. Both currently land on the downstream
33333        // `BadByteMagnitude` / `BadDurationMagnitude` arm at parse time
33334        // with the byte-shape diagnostic intact; the render-determinism
33335        // contract is unbroken on those inputs today. This test pins
33336        // the predicate's exclusion so a future widening that starts
33337        // flagging BOM / ZWSP here surfaces as a test failure rather
33338        // than a silent over-fire on a class the downstream arm
33339        // already closes.
33340        assert!(find_non_ascii_whitespace_char("\u{FEFF}64MiB").is_none());
33341        assert!(find_non_ascii_whitespace_char("\u{200B}30s").is_none());
33342    }
33343
33344    // ── shared predicate: is_leading_zero_padded_magnitude ──────────────
33345    //
33346    // Pins the accepted / rejected set of the lifted leading-zero
33347    // predicate every typed-magnitude codec in caixa-core calls
33348    // (`parse_byte_size` / `parse_duration` / `parse_millicores` /
33349    // shared `duration_codec` / `rate_limit_codec`). Same lifted-
33350    // source-of-truth discipline the peer whitespace predicates
33351    // (`find_ascii_whitespace_byte` / `find_non_ascii_whitespace_char`)
33352    // carry — drift between any two codec sites' rejection set becomes
33353    // a single-edit fix at this predicate.
33354
33355    #[test]
33356    fn is_leading_zero_padded_magnitude_accepts_canonical_forms() {
33357        // Complement-side pin: every canonical form the typed-magnitude
33358        // `render_*` canonicalizers emit — the single-byte `"0"` case
33359        // and every non-leading-zero magnitude — returns `false`.
33360        assert!(!is_leading_zero_padded_magnitude("0"));
33361        assert!(!is_leading_zero_padded_magnitude("1"));
33362        assert!(!is_leading_zero_padded_magnitude("64"));
33363        assert!(!is_leading_zero_padded_magnitude("500"));
33364        assert!(!is_leading_zero_padded_magnitude("1024"));
33365        assert!(!is_leading_zero_padded_magnitude("999999"));
33366        // Empty magnitude is not a leading-zero shape either — the
33367        // upstream `digit_only` gate at each codec site refuses empty
33368        // magnitudes on its own arm before this predicate is consulted.
33369        assert!(!is_leading_zero_padded_magnitude(""));
33370        // Non-digit-only bodies are outside the predicate's scope — the
33371        // upstream `digit_only` gate refuses them with its own
33372        // `NonInteger*` / `Bad*` diagnostic; this predicate is invoked
33373        // only after that gate accepts.
33374        assert!(!is_leading_zero_padded_magnitude("a"));
33375        assert!(!is_leading_zero_padded_magnitude("1.5"));
33376    }
33377
33378    #[test]
33379    fn is_leading_zero_padded_magnitude_flags_two_byte_leading_zero() {
33380        // The minimal leading-zero drift shape: two-byte magnitude
33381        // starting with `'0'` — `"00"` / `"01"` / `"09"`. Every one
33382        // round-trips through the peer codecs' `render_*` to the
33383        // leading-zero-stripped form (`"0"` / `"1"` / `"9"`).
33384        assert!(is_leading_zero_padded_magnitude("00"));
33385        assert!(is_leading_zero_padded_magnitude("01"));
33386        assert!(is_leading_zero_padded_magnitude("09"));
33387    }
33388
33389    #[test]
33390    fn is_leading_zero_padded_magnitude_flags_multi_byte_leading_zero() {
33391        // The canonical paste-from-fixed-width-alignment /
33392        // paste-from-columnar-report drift class each codec's
33393        // `render_*` emits the stripped form for: `"0064"` (byte-size
33394        // magnitude), `"030"` (duration magnitude), `"0500"`
33395        // (millicores magnitude), `"0100"` (rate-limit magnitude),
33396        // `"01024"` (multi-digit byte-size magnitude).
33397        assert!(is_leading_zero_padded_magnitude("0064"));
33398        assert!(is_leading_zero_padded_magnitude("030"));
33399        assert!(is_leading_zero_padded_magnitude("0500"));
33400        assert!(is_leading_zero_padded_magnitude("0100"));
33401        assert!(is_leading_zero_padded_magnitude("01024"));
33402        // All-zeros multi-byte magnitude — `"000"` / `"0000"` — every
33403        // one round-trips to `"0"`. The single-byte `"0"` case is the
33404        // canonical zero and stays accepted; the multi-byte all-zero
33405        // shape is leading-zero drift.
33406        assert!(is_leading_zero_padded_magnitude("000"));
33407        assert!(is_leading_zero_padded_magnitude("0000"));
33408    }
33409
33410    #[test]
33411    fn is_leading_zero_padded_magnitude_pins_single_zero_boundary() {
33412        // The single-byte magnitude `"0"` is the canonical zero the
33413        // peer codecs' `render_*` canonicalizers emit for the zero
33414        // value verbatim (`render_byte_size(0)` = `"0"`,
33415        // `render_duration(Duration::ZERO)` = `"0s"` with `"0"` as
33416        // the magnitude, `render_millicores(0)` = `"0m"` with `"0"`
33417        // as the magnitude, `RateLimit::render` for rate=0 = `"0/s"`
33418        // with `"0"` as the magnitude). Pinning this boundary so a
33419        // future widening that starts flagging the single-byte `"0"`
33420        // here surfaces as a test failure rather than a silent break
33421        // of the codec-layer / typed-validate-layer partition — the
33422        // semantic-zero gates at the typed-validate layer above
33423        // (`LimitsError::MemoryZero`, `LimitsError::WallClockZero`,
33424        // `LimitsError::CpuZero`, `SupervisorError::ZeroRestartWindow`,
33425        // `AplicacaoError::PolicyTimeoutZero` /
33426        // `PolicyCircuitBreakerWindowZero` / `PolicyRateLimitZero`)
33427        // are what refuse zero-magnitude authoring, not this codec-
33428        // layer predicate.
33429        assert!(!is_leading_zero_padded_magnitude("0"));
33430    }
33431
33432    // ── shared predicate: is_digit_only_magnitude ───────────────────────
33433    //
33434    // Pins the accepted / rejected set of the lifted digit-only
33435    // predicate every typed-magnitude codec in caixa-core calls
33436    // (`parse_byte_size` / `parse_duration` / `parse_millicores` /
33437    // shared `duration_codec` / `rate_limit_codec`). Same lifted-
33438    // source-of-truth discipline the peer canonical-form predicates
33439    // (`find_ascii_whitespace_byte` / `find_non_ascii_whitespace_char`
33440    // / `is_leading_zero_padded_magnitude`) carry — drift between any
33441    // two codec sites' rejection set becomes a single-edit fix at
33442    // this predicate.
33443
33444    #[test]
33445    fn is_digit_only_magnitude_accepts_canonical_forms() {
33446        // Complement-side pin: every canonical form the typed-magnitude
33447        // `render_*` canonicalizers emit — the single-byte `"0"` case
33448        // and every non-zero non-leading-zero magnitude — returns
33449        // `true`.
33450        assert!(is_digit_only_magnitude("0"));
33451        assert!(is_digit_only_magnitude("1"));
33452        assert!(is_digit_only_magnitude("64"));
33453        assert!(is_digit_only_magnitude("500"));
33454        assert!(is_digit_only_magnitude("1024"));
33455        assert!(is_digit_only_magnitude("999999"));
33456    }
33457
33458    #[test]
33459    fn is_digit_only_magnitude_flags_empty_magnitude() {
33460        // Defense-in-depth: the empty string is non-digit-only per the
33461        // predicate's contract, so a future codec reaching for this
33462        // predicate before landing its own upstream empty-magnitude
33463        // arm still routes empty input to the non-canonical branch
33464        // rather than silently accepting it via the vacuous
33465        // `bytes().all(_)` truth on the empty byte-slice.
33466        assert!(!is_digit_only_magnitude(""));
33467    }
33468
33469    #[test]
33470    fn is_digit_only_magnitude_flags_leading_sign() {
33471        // The paste-from-signed-report drift class every codec's
33472        // `render_*` emits the unsigned form for. On current Rust
33473        // `u64::from_str` / `u32::from_str` permissively accept a
33474        // leading `+` (`"+500"` → 500), so `"+30"`, `"+500"`, `"+100"`
33475        // survive the parser and round-trip through `render_*` to the
33476        // sign-stripped form (`"30"`, `"500"`, `"100"`) — a *different*
33477        // canonical string on the next emit, breaking the THEORY.md
33478        // Part V render-determinism contract. The digit-only gate is
33479        // what closes the leading-sign class at each codec site.
33480        assert!(!is_digit_only_magnitude("+30"));
33481        assert!(!is_digit_only_magnitude("+500"));
33482        assert!(!is_digit_only_magnitude("+100"));
33483        assert!(!is_digit_only_magnitude("-30"));
33484        assert!(!is_digit_only_magnitude("-1"));
33485    }
33486
33487    #[test]
33488    fn is_digit_only_magnitude_flags_fractional_and_decimal() {
33489        // The paste-from-floating-point-source drift class every
33490        // codec's `render_*` emits the integer form for. On the peer
33491        // duration codec the parser accepts `f64`-shaped magnitudes
33492        // (`"1.5s"` → 1500ms → `"1500ms"`, `"1.0s"` → 1s → `"1s"`,
33493        // `"0.5m"` → 30s → `"30s"`) — a *different* canonical string
33494        // on the next emit, breaking the THEORY.md Part V render-
33495        // determinism contract. The digit-only gate closes the
33496        // decimal-point / fractional / exponent class at each codec
33497        // site.
33498        assert!(!is_digit_only_magnitude("1.5"));
33499        assert!(!is_digit_only_magnitude("1.0"));
33500        assert!(!is_digit_only_magnitude("0.5"));
33501        assert!(!is_digit_only_magnitude("1e3"));
33502        assert!(!is_digit_only_magnitude(".5"));
33503        assert!(!is_digit_only_magnitude("5."));
33504    }
33505
33506    #[test]
33507    fn is_digit_only_magnitude_flags_alphabetic_and_symbol_bytes() {
33508        // Complement-side pin on the "garbage" branch: alphabetic
33509        // bytes / symbol bytes / whitespace bytes each land on the
33510        // non-digit-only side. At the codec site the downstream
33511        // "non-canonical-but-numeric vs garbage" partition surfaces
33512        // these with the narrower `Bad*` diagnostic; here the
33513        // predicate simply reports `false`.
33514        assert!(!is_digit_only_magnitude("a"));
33515        assert!(!is_digit_only_magnitude("64a"));
33516        assert!(!is_digit_only_magnitude("6_4"));
33517        assert!(!is_digit_only_magnitude("64 "));
33518        assert!(!is_digit_only_magnitude(" 64"));
33519    }
33520
33521    #[test]
33522    fn is_digit_only_magnitude_pins_leading_zero_boundary() {
33523        // The leading-zero-padded magnitude shape stays inside the
33524        // digit-only accepted set at this predicate — every byte is
33525        // an ASCII digit. The peer
33526        // [`is_leading_zero_padded_magnitude`] predicate closes the
33527        // leading-zero drift class on a separate, strictly-later arm
33528        // at each codec site. Pinning this partition so a future
33529        // widening that collapses the two arms surfaces as a test
33530        // failure rather than a silent break of the two-predicate
33531        // codec-layer discipline.
33532        assert!(is_digit_only_magnitude("00"));
33533        assert!(is_digit_only_magnitude("0064"));
33534        assert!(is_digit_only_magnitude("0500"));
33535    }
33536
33537    // ── require_positive_bounded_{u32,u64} ──────────────────────────────
33538
33539    #[derive(Debug, PartialEq, Eq)]
33540    enum TestErr {
33541        Zero,
33542        Cap(u64),
33543    }
33544
33545    #[test]
33546    fn require_positive_bounded_u32_accepts_in_range() {
33547        assert_eq!(
33548            require_positive_bounded_u32::<TestErr>(
33549                1,
33550                10,
33551                || TestErr::Zero,
33552                |v| TestErr::Cap(u64::from(v))
33553            ),
33554            Ok(())
33555        );
33556        assert_eq!(
33557            require_positive_bounded_u32::<TestErr>(
33558                10,
33559                10,
33560                || TestErr::Zero,
33561                |v| TestErr::Cap(u64::from(v))
33562            ),
33563            Ok(())
33564        );
33565        assert_eq!(
33566            require_positive_bounded_u32::<TestErr>(
33567                5,
33568                10,
33569                || TestErr::Zero,
33570                |v| TestErr::Cap(u64::from(v))
33571            ),
33572            Ok(())
33573        );
33574    }
33575
33576    #[test]
33577    fn require_positive_bounded_u32_rejects_zero_with_self_locating_diagnostic() {
33578        // The zero-floor arm strictly precedes the cap arm — a value of
33579        // 0 surfaces the `on_zero` callback's discriminator (which every
33580        // per-axis error variant documents an omit-axis remediation for),
33581        // never the `on_cap_exceeded` callback (which would misframe
33582        // "0 > cap == false" as an above-cap value).
33583        assert_eq!(
33584            require_positive_bounded_u32::<TestErr>(
33585                0,
33586                10,
33587                || TestErr::Zero,
33588                |v| TestErr::Cap(u64::from(v))
33589            ),
33590            Err(TestErr::Zero)
33591        );
33592        // Pin the ordering under the degenerate cap == 0 boundary: even
33593        // when the cap itself is 0 (never valid for a positive-bounded
33594        // axis in production, but pins the ordering contract), 0 routes
33595        // through the zero arm — not the cap arm.
33596        assert_eq!(
33597            require_positive_bounded_u32::<TestErr>(
33598                0,
33599                0,
33600                || TestErr::Zero,
33601                |v| TestErr::Cap(u64::from(v))
33602            ),
33603            Err(TestErr::Zero)
33604        );
33605    }
33606
33607    #[test]
33608    fn require_positive_bounded_u32_rejects_above_cap_with_value_threaded() {
33609        assert_eq!(
33610            require_positive_bounded_u32::<TestErr>(
33611                11,
33612                10,
33613                || TestErr::Zero,
33614                |v| TestErr::Cap(u64::from(v))
33615            ),
33616            Err(TestErr::Cap(11))
33617        );
33618        assert_eq!(
33619            require_positive_bounded_u32::<TestErr>(
33620                u32::MAX,
33621                10,
33622                || TestErr::Zero,
33623                |v| TestErr::Cap(u64::from(v))
33624            ),
33625            Err(TestErr::Cap(u64::from(u32::MAX)))
33626        );
33627    }
33628
33629    #[test]
33630    fn require_positive_bounded_u64_accepts_in_range() {
33631        assert_eq!(
33632            require_positive_bounded_u64::<TestErr>(1, 10, || TestErr::Zero, TestErr::Cap),
33633            Ok(())
33634        );
33635        assert_eq!(
33636            require_positive_bounded_u64::<TestErr>(10, 10, || TestErr::Zero, TestErr::Cap),
33637            Ok(())
33638        );
33639    }
33640
33641    #[test]
33642    fn require_positive_bounded_u64_rejects_zero_and_above_cap() {
33643        assert_eq!(
33644            require_positive_bounded_u64::<TestErr>(0, 10, || TestErr::Zero, TestErr::Cap),
33645            Err(TestErr::Zero)
33646        );
33647        assert_eq!(
33648            require_positive_bounded_u64::<TestErr>(11, 10, || TestErr::Zero, TestErr::Cap),
33649            Err(TestErr::Cap(11))
33650        );
33651        assert_eq!(
33652            require_positive_bounded_u64::<TestErr>(u64::MAX, 10, || TestErr::Zero, TestErr::Cap),
33653            Err(TestErr::Cap(u64::MAX))
33654        );
33655    }
33656
33657    // ── require_positive_canonical_bounded_duration ─────────────────────
33658
33659    #[derive(Debug, PartialEq, Eq)]
33660    enum DurationTestErr {
33661        Zero,
33662        NotCanonical(Duration),
33663        Cap(Duration),
33664    }
33665
33666    #[test]
33667    fn require_positive_canonical_bounded_duration_accepts_in_range_canonical_values() {
33668        // Every canonical integer-millisecond `Duration` in
33669        // `1ms..=cap` — the shared accepted set every typed-`Duration`
33670        // consumer inherits — must pass the gate. Pin the canonical
33671        // set here so a future tightening surfaces as a test failure
33672        // rather than a silent narrowing at one of the four consumer
33673        // sites (`:politicas :timeout`, `:circuit-breaker :window`,
33674        // `:limits :wall-clock`, `:supervisor :restart-window`).
33675        let cap = Duration::from_secs(3600); // matches the 1h peer caps
33676        for value in [
33677            Duration::from_millis(1),
33678            Duration::from_millis(500),
33679            Duration::from_millis(1500),
33680            Duration::from_secs(30),
33681            Duration::from_secs(60),
33682            cap,
33683        ] {
33684            assert_eq!(
33685                require_positive_canonical_bounded_duration::<DurationTestErr>(
33686                    value,
33687                    cap,
33688                    || DurationTestErr::Zero,
33689                    DurationTestErr::NotCanonical,
33690                    DurationTestErr::Cap,
33691                ),
33692                Ok(()),
33693                "canonical in-range value {value:?} must pass the gate",
33694            );
33695        }
33696    }
33697
33698    #[test]
33699    fn require_positive_canonical_bounded_duration_rejects_zero_before_canonical_and_cap() {
33700        // The zero-floor arm strictly precedes the canonical-form and
33701        // cap arms — `Duration::ZERO` (which has `subsec_nanos() == 0`
33702        // and would pass the canonical-form predicate; and would pass
33703        // the cap arm since 0 ≤ cap) routes through the zero arm so
33704        // the caller's self-locating `on_zero` diagnostic (every
33705        // per-axis error variant documents an omit-axis remediation
33706        // for) is surfaced, not the misleading no-op the two later
33707        // arms would return.
33708        let cap = Duration::from_secs(3600);
33709        assert_eq!(
33710            require_positive_canonical_bounded_duration::<DurationTestErr>(
33711                Duration::ZERO,
33712                cap,
33713                || DurationTestErr::Zero,
33714                DurationTestErr::NotCanonical,
33715                DurationTestErr::Cap,
33716            ),
33717            Err(DurationTestErr::Zero),
33718        );
33719        // The degenerate `cap == Duration::ZERO` boundary: `Duration::ZERO`
33720        // still routes through the zero arm — the ordering contract holds
33721        // even when the cap itself is zero (never a valid production cap
33722        // for a positive-bounded axis, but pins the arm ordering).
33723        assert_eq!(
33724            require_positive_canonical_bounded_duration::<DurationTestErr>(
33725                Duration::ZERO,
33726                Duration::ZERO,
33727                || DurationTestErr::Zero,
33728                DurationTestErr::NotCanonical,
33729                DurationTestErr::Cap,
33730            ),
33731            Err(DurationTestErr::Zero),
33732        );
33733    }
33734
33735    #[test]
33736    fn require_positive_canonical_bounded_duration_rejects_sub_millisecond_before_cap() {
33737        // The canonical-form arm strictly precedes the cap arm — a
33738        // `Duration` that is *both* sub-millisecond and above-cap must
33739        // surface the more fundamental round-trip-shape diagnostic
33740        // first (the cap arm's `1ms..=<cap>` remediation prose would
33741        // be misleading when no integer-ms form of the offending
33742        // value exists). Pin the ordering across the value grid.
33743        let cap = Duration::from_secs(1);
33744        for value in [
33745            Duration::from_micros(1),
33746            Duration::from_micros(500),
33747            Duration::from_micros(1500),
33748            Duration::from_nanos(1),
33749            Duration::from_nanos(999_999),
33750            Duration::from_nanos(1_000_001),
33751            // Sub-millisecond *and* above-cap: canonical-form arm wins.
33752            cap + Duration::from_nanos(1),
33753        ] {
33754            let result = require_positive_canonical_bounded_duration::<DurationTestErr>(
33755                value,
33756                cap,
33757                || DurationTestErr::Zero,
33758                DurationTestErr::NotCanonical,
33759                DurationTestErr::Cap,
33760            );
33761            assert_eq!(
33762                result,
33763                Err(DurationTestErr::NotCanonical(value)),
33764                "sub-millisecond {value:?} must surface NotCanonical before Cap",
33765            );
33766        }
33767    }
33768
33769    #[test]
33770    fn require_positive_canonical_bounded_duration_rejects_above_cap_with_value_threaded() {
33771        // The cap arm surfaces the offending value verbatim so the
33772        // caller's `on_cap_exceeded` variant threads it into its
33773        // discriminator field (`timeout` / `window` / `wall_clock`).
33774        // The value grid covers the canonical `<n>ms` / `<n>s`
33775        // integer-millisecond shape past the 1h cap so the arm ordering
33776        // (canonical-form first) doesn't intercept these values.
33777        let cap = Duration::from_secs(3600);
33778        for value in [
33779            cap + Duration::from_millis(1),
33780            cap + Duration::from_secs(1),
33781            Duration::from_secs(24 * 3600), // 24h — canonical string
33782            Duration::from_secs(7 * 24 * 3600), // 7d
33783        ] {
33784            assert_eq!(
33785                require_positive_canonical_bounded_duration::<DurationTestErr>(
33786                    value,
33787                    cap,
33788                    || DurationTestErr::Zero,
33789                    DurationTestErr::NotCanonical,
33790                    DurationTestErr::Cap,
33791                ),
33792                Err(DurationTestErr::Cap(value)),
33793                "above-cap canonical value {value:?} must thread through the cap arm",
33794            );
33795        }
33796    }
33797
33798    // ── require_valid_versao_requirement ────────────────────────────────
33799
33800    #[derive(Debug, PartialEq, Eq)]
33801    enum VersaoTestErr {
33802        Empty,
33803        Invalid(String),
33804    }
33805
33806    #[test]
33807    fn require_valid_versao_requirement_accepts_canonical_forms() {
33808        // Every Cargo-shaped requirement string the substrate accepts on
33809        // any `:versao` axis (`:deps`, `:membros`, `:children`) must pass
33810        // the shared gate — pin the canonical set here so a future
33811        // tightening surfaces as a test failure rather than a silent
33812        // narrowing at one of the three consumer sites. Same accepted set
33813        // as `accepts_canonical_membro_versao_forms` /
33814        // `accepts_canonical_dep_versao_forms` on the sibling per-axis
33815        // pins.
33816        for form in [
33817            "^0.1",      // caret — minor-range pin (the most common shape)
33818            "~0.1.2",    // tilde — patch-range pin
33819            "0.1.0",     // exact — single-version pin
33820            "*",         // wildcard — explicitly any-version (VersionReq::STAR)
33821            ">=0.1, <2", // multi-range — comma-separated comparators
33822        ] {
33823            assert_eq!(
33824                require_valid_versao_requirement::<VersaoTestErr>(
33825                    form,
33826                    || VersaoTestErr::Empty,
33827                    VersaoTestErr::Invalid,
33828                ),
33829                Ok(()),
33830                "canonical form {form:?} must pass the gate",
33831            );
33832        }
33833    }
33834
33835    #[test]
33836    fn require_valid_versao_requirement_rejects_empty_before_parse() {
33837        // The empty-first arm strictly precedes the parse arm. Without
33838        // this arm the parser silently widens `""` to
33839        // `VersionReq { comparators: [] }` (semantically `*`) — a
33840        // "silent widening" footgun the three consumer sites each
33841        // documented in their `MembroVersaoEmpty` / `EmptyChildVersion` /
33842        // `VersaoEmpty` variants and now inherit by construction.
33843        assert_eq!(
33844            require_valid_versao_requirement::<VersaoTestErr>(
33845                "",
33846                || VersaoTestErr::Empty,
33847                VersaoTestErr::Invalid,
33848            ),
33849            Err(VersaoTestErr::Empty),
33850        );
33851    }
33852
33853    #[test]
33854    fn require_valid_versao_requirement_rejects_malformed_with_reason_threaded() {
33855        // The canonical malformed-shape set the three consumer sites
33856        // formerly each re-tested inline. The gate threads the
33857        // parser's `to_string()` output through as the invalid arm's
33858        // `reason:` verbatim — the field the three sibling error
33859        // variants (`{Dep,Membro,Child}VersaoInvalid.reason`) each
33860        // carry to the author's remediation prose.
33861        for bad in [
33862            "^^0.1", // doubled-caret typo
33863            "v0.1",  // git-tag-shape leaking into requirement slot
33864            "abc",   // gibberish
33865            "~~",    // stacked-operator gibberish
33866        ] {
33867            let result = require_valid_versao_requirement::<VersaoTestErr>(
33868                bad,
33869                || VersaoTestErr::Empty,
33870                VersaoTestErr::Invalid,
33871            );
33872            match result {
33873                Err(VersaoTestErr::Invalid(reason)) => {
33874                    assert!(
33875                        !reason.is_empty(),
33876                        "invalid arm must thread a non-empty reason for {bad:?}",
33877                    );
33878                }
33879                other => panic!("expected Invalid for {bad:?}, got {other:?}"),
33880            }
33881        }
33882    }
33883
33884    // ── require_valid_dns_1123_label ────────────────────────────────────
33885
33886    #[derive(Debug, PartialEq, Eq)]
33887    enum LabelTestErr {
33888        Empty,
33889        Invalid(String),
33890    }
33891
33892    #[test]
33893    fn require_valid_dns_1123_label_accepts_canonical_forms() {
33894        // Every DNS-1123-label-shaped Servico-name reference the substrate
33895        // accepts on any name axis (`:membros :caixa`, `:placement :clusters`,
33896        // `:placement :affinity`, `:contratos :de`/`:para`, `:entrada :para`,
33897        // `:children :caixa`, `:nome`, `:upgrade-from :module`) must pass
33898        // the shared gate — pin the canonical set here so a future
33899        // tightening surfaces as a test failure rather than a silent
33900        // narrowing at one of the eight consumer sites. Same accepted set
33901        // as the sibling per-axis DNS-1123-label pins already carry.
33902        for form in [
33903            "hello-rio",                         // canonical dashed
33904            "cart",                              // single-token
33905            "rio-1",                             // trailing digit
33906            "1-rio",                             // leading digit
33907            "a",                                 // one byte
33908            &"a".repeat(DNS_1123_LABEL_MAX_LEN), // max length exact
33909        ] {
33910            assert_eq!(
33911                require_valid_dns_1123_label::<LabelTestErr>(
33912                    form,
33913                    || LabelTestErr::Empty,
33914                    LabelTestErr::Invalid,
33915                ),
33916                Ok(()),
33917                "canonical form {form:?} must pass the gate",
33918            );
33919        }
33920    }
33921
33922    #[test]
33923    fn require_valid_dns_1123_label_rejects_empty_before_shape() {
33924        // The empty-first arm strictly precedes the shape arm so a
33925        // literal `""` surfaces each per-axis error variant's narrower
33926        // self-locating `_Empty` diagnostic rather than the shared
33927        // predicate's generic "must not be empty" prose the shape arm
33928        // would thread through — the same "misframed generic diagnostic"
33929        // footgun the peer [`require_valid_versao_requirement`] closes
33930        // on its empty arm. The eight consumer sites each documented
33931        // this ordering in their `MembroCaixaEmpty` / `PlacementClusterEmpty`
33932        // / `PlacementAffinityEmpty` / `ContratoCaixaEmpty` /
33933        // `EntradaParaEmpty` / `NomeEmpty` / `EmptyChildName` /
33934        // `ModuleEmpty` variants and now inherit it by construction.
33935        assert_eq!(
33936            require_valid_dns_1123_label::<LabelTestErr>(
33937                "",
33938                || LabelTestErr::Empty,
33939                LabelTestErr::Invalid,
33940            ),
33941            Err(LabelTestErr::Empty),
33942        );
33943    }
33944
33945    #[test]
33946    fn require_valid_dns_1123_label_rejects_malformed_with_reason_threaded() {
33947        // The canonical malformed-shape set the eight consumer sites
33948        // formerly each re-tested inline. The gate threads the
33949        // predicate's shape-shaped reason through as the invalid arm's
33950        // `reason:` verbatim — the field every sibling error variant
33951        // (`{MembroCaixa,PlacementCluster,PlacementAffinity,ContratoCaixa,
33952        // EntradaPara,Nome,ChildCaixa,Module}Invalid.reason`) each
33953        // carry to the author's remediation prose.
33954        for bad in [
33955            "Rio",       // uppercase — the canonical TitleCase-from-an-ADR typo
33956            "my_cart",   // underscore — the Python-module-name leak
33957            "team.cart", // dot — the namespace-dot-on-a-label confusion
33958            "-cart",     // leading hyphen — boundary violation
33959            "cart-",     // trailing hyphen — boundary violation
33960        ] {
33961            let result = require_valid_dns_1123_label::<LabelTestErr>(
33962                bad,
33963                || LabelTestErr::Empty,
33964                LabelTestErr::Invalid,
33965            );
33966            match result {
33967                Err(LabelTestErr::Invalid(reason)) => {
33968                    assert!(
33969                        !reason.is_empty(),
33970                        "invalid arm must thread a non-empty reason for {bad:?}",
33971                    );
33972                }
33973                other => panic!("expected Invalid for {bad:?}, got {other:?}"),
33974            }
33975        }
33976    }
33977
33978    // ── require_sandboxed_lisp_path ─────────────────────────────────────
33979
33980    #[derive(Debug, PartialEq, Eq)]
33981    enum LispPathTestErr {
33982        Empty,
33983        Absolute,
33984        ParentEscape,
33985        NonLisp,
33986    }
33987
33988    fn call_require_sandboxed_lisp_path(path: &Path) -> Result<(), LispPathTestErr> {
33989        require_sandboxed_lisp_path(
33990            path,
33991            || LispPathTestErr::Empty,
33992            || LispPathTestErr::Absolute,
33993            || LispPathTestErr::ParentEscape,
33994            || LispPathTestErr::NonLisp,
33995        )
33996    }
33997
33998    #[test]
33999    fn require_sandboxed_lisp_path_accepts_canonical_forms() {
34000        // Every sandboxed-relative `.lisp`-terminating path the substrate
34001        // accepts on either M2 tatara-lisp source-path axis (`:behavior :on-*`
34002        // callback paths, `:upgrade-from :state-change :script`) must pass
34003        // the shared gate. Pin the canonical set here so a future tightening
34004        // surfaces as a test failure rather than a silent narrowing at one
34005        // of the two consumer sites.
34006        for form in [
34007            "lib/init.lisp",                     // canonical example
34008            "lib/handlers.lisp",                 // multi-callback shape
34009            "lib/migrations/v01-to-v02.lisp",    // nested-directory shape
34010            "a.lisp",                            // one-byte stem
34011            "lib/deep/nested/path/to/file.lisp", // deeply nested
34012        ] {
34013            assert_eq!(
34014                call_require_sandboxed_lisp_path(Path::new(form)),
34015                Ok(()),
34016                "canonical sandboxed `.lisp` form {form:?} must pass the gate",
34017            );
34018        }
34019    }
34020
34021    #[test]
34022    fn require_sandboxed_lisp_path_rejects_empty_before_all_later_arms() {
34023        // The empty-first arm strictly precedes every downstream arm — a
34024        // literal `""` (which the is_absolute check would return false on,
34025        // which carries no ParentDir component, and whose extension is
34026        // absent) routes through the `on_empty` closure so the caller's
34027        // narrower self-locating `_Empty` / `_EmptyScript` diagnostic fires,
34028        // not a misleading `_Absolute` / `_ParentEscape` / `_NonLisp` miss
34029        // downstream. Peer of every zero-first arm ordering the sibling
34030        // require_positive_bounded_* helpers already carry.
34031        assert_eq!(
34032            call_require_sandboxed_lisp_path(Path::new("")),
34033            Err(LispPathTestErr::Empty),
34034        );
34035    }
34036
34037    #[test]
34038    fn require_sandboxed_lisp_path_rejects_absolute_before_parent_escape_and_non_lisp() {
34039        // The absolute arm strictly precedes the parent-escape and
34040        // non-`.lisp`-extension arms — an absolute path (regardless of
34041        // whether it also carries `..` components or a non-`.lisp`
34042        // extension) routes through the `on_absolute` closure so the
34043        // caller's `_Absolute` / `_AbsoluteScript` diagnostic fires with
34044        // its "must be relative to the caixa root" remediation, not the
34045        // misleading later arms. Pin the ordering across the value grid
34046        // covering "absolute + parent-escape" and "absolute + non-`.lisp`"
34047        // compound-violation shapes so a future arm-reorder silently
34048        // narrowing the accepted set would surface at build time.
34049        for absolute in [
34050            "/etc/passwd",       // canonical absolute
34051            "/lib/init.lisp",    // absolute + `.lisp` (extension arm never reached)
34052            "/lib/../init.lisp", // absolute + parent-escape (later arm never reached)
34053            "/etc/init.txt",     // absolute + non-`.lisp`
34054        ] {
34055            assert_eq!(
34056                call_require_sandboxed_lisp_path(Path::new(absolute)),
34057                Err(LispPathTestErr::Absolute),
34058                "absolute path {absolute:?} must route through Absolute arm",
34059            );
34060        }
34061    }
34062
34063    #[test]
34064    fn require_sandboxed_lisp_path_rejects_parent_escape_before_non_lisp() {
34065        // The parent-escape arm strictly precedes the non-`.lisp`-extension
34066        // arm — a relative path carrying any `..` component routes through
34067        // the `on_parent_escape` closure so the caller's `_ParentEscape` /
34068        // `_ParentEscapeScript` diagnostic fires with its "must not
34069        // traverse above the caixa root" remediation, not the misleading
34070        // extension-shape arm. Pin the ordering across leading / mid-path
34071        // / trailing parent-escape positions plus the compound
34072        // "parent-escape + non-`.lisp`" shape.
34073        for escape in [
34074            "../sibling/x.lisp",  // leading `..`
34075            "lib/../other.lisp",  // mid-path `..`
34076            "lib/handlers/../..", // trailing `..`
34077            "../sibling/x.txt",   // parent-escape + non-`.lisp`
34078        ] {
34079            assert_eq!(
34080                call_require_sandboxed_lisp_path(Path::new(escape)),
34081                Err(LispPathTestErr::ParentEscape),
34082                "parent-escaping path {escape:?} must route through ParentEscape arm",
34083            );
34084        }
34085    }
34086
34087    #[test]
34088    fn require_sandboxed_lisp_path_rejects_non_lisp_only_after_all_path_shape_arms_accept() {
34089        // The non-`.lisp`-extension arm fires only when every prior arm
34090        // (empty / absolute / parent-escape) accepts the path — a
34091        // sandboxed relative path whose only violation is a non-`.lisp`
34092        // terminating extension routes through the `on_non_lisp` closure
34093        // so the caller's `_NonLispExtension` / `_NonLispExtensionScript`
34094        // diagnostic fires with its `.lisp`-remediation prose. Pin the
34095        // downstream-most-arm reachability across the canonical
34096        // `.txt`/`.rs`/no-extension/double-extension-shadow shape set the
34097        // two consumer sites' error variants each document.
34098        for bad_ext in [
34099            "lib/init.txt",      // wrong extension
34100            "lib/init.rs",       // Rust source leaked into caixa
34101            "lib/init.lisp.bak", // double-extension shadow
34102            "lib/init",          // no extension
34103            "lib/migrations",    // no extension, no dot
34104            "lib/init.LISP",     // uppercase — case-sensitive gate
34105        ] {
34106            assert_eq!(
34107                call_require_sandboxed_lisp_path(Path::new(bad_ext)),
34108                Err(LispPathTestErr::NonLisp),
34109                "non-`.lisp` path {bad_ext:?} must route through NonLisp arm",
34110            );
34111        }
34112    }
34113
34114    #[test]
34115    fn require_sandboxed_lisp_path_ordering_matches_inline_pre_lift_cascade() {
34116        // Byte-for-byte the same `Empty → Absolute → ParentEscape → NonLisp`
34117        // arm-ordering the two consumer sites (`validate_callback_path` in
34118        // `caixa-core::behavior`, `UpgradeInstruction::validate`'s
34119        // `StateChange` arm in `caixa-core::upgrade`) each formerly inlined
34120        // verbatim. This pin catches any future reorder that would
34121        // silently reshape the diagnostic dispatch at either site — the
34122        // helper's ordering IS the two sites' ordering, not a re-derived
34123        // convention. Pins the same
34124        // smallest-scope-arm-fires-last three-path drift-detection
34125        // posture the peer `require_positive_bounded_*` /
34126        // `require_positive_canonical_bounded_duration` helpers already
34127        // carry on their own arm sets.
34128        assert_eq!(
34129            call_require_sandboxed_lisp_path(Path::new("")),
34130            Err(LispPathTestErr::Empty),
34131        );
34132        assert_eq!(
34133            call_require_sandboxed_lisp_path(Path::new("/abs/x.lisp")),
34134            Err(LispPathTestErr::Absolute),
34135        );
34136        assert_eq!(
34137            call_require_sandboxed_lisp_path(Path::new("../x.lisp")),
34138            Err(LispPathTestErr::ParentEscape),
34139        );
34140        assert_eq!(
34141            call_require_sandboxed_lisp_path(Path::new("lib/x.txt")),
34142            Err(LispPathTestErr::NonLisp),
34143        );
34144        assert_eq!(
34145            call_require_sandboxed_lisp_path(Path::new("lib/x.lisp")),
34146            Ok(()),
34147        );
34148    }
34149
34150    #[test]
34151    fn gateway_api_hostname_max_len_pins_canonical_value() {
34152        // Pin the actual byte count so a typo in this lift can't silently
34153        // rebrand the K8s Gateway API v1 `Listener.hostname` /
34154        // `HTTPRoute.spec.hostnames[]` admission-schema `maxLength:` cap
34155        // the `AplicacaoSpec::validate` `:entrada :host` total-length arm
34156        // reads. The value is part of the cluster-side contract with
34157        // every Gateway API v1 CRD schema validator (apiserver-side +
34158        // Cilium / Envoy Gateway / Istio / NGINX per-implementation
34159        // webhooks) — the OpenAPI schema on the Hostname type binds
34160        // `maxLength: 253` verbatim (RFC 1035 / RFC 1123 DNS name limit:
34161        // 255 wire bytes minus the trailing-dot + one length prefix), so
34162        // a drifted value at either the aplicacao-side validator or a
34163        // downstream renderer's per-host validator silently emits a
34164        // Gateway / HTTPRoute the apiserver rejects at admission time
34165        // with an opaque `field is invalid` diagnostic far from the
34166        // caixa.lisp source line. Changing this value is a coordinated
34167        // Gateway API promotion alongside the upstream SIG-Network
34168        // Hostname schema evolution, not an incidental edit. Peer to
34169        // [`GATEWAY_API_HTTP_PATH_MAX_LEN`] (1024) on the sibling
34170        // per-route path-value cap axis — both are apiserver-side
34171        // `maxLength:` bounds on Gateway API v1 landing sites, both lift
34172        // to `caixa-core::render` so the M4 CR materializer's per-axis
34173        // validators (per-host, per-path) read from one place.
34174        assert_eq!(GATEWAY_API_HOSTNAME_MAX_LEN, 253);
34175    }
34176
34177    #[test]
34178    fn gateway_api_hostname_max_len_exceeds_dns_1123_label_max_len() {
34179        // Cross-axis structural invariant: every `.`-separated label in
34180        // a Gateway API v1 Hostname is a DNS-1123 label, so the total
34181        // Hostname cap must strictly exceed the per-label cap — otherwise
34182        // even a single-label host `"foo"` couldn't reach the per-label
34183        // ceiling before hitting the total-length ceiling, and the
34184        // `AplicacaoSpec::validate` `:entrada :host` per-label arm at
34185        // `validate_entrada_host` would be structurally unreachable via
34186        // the total-length arm's own ordering. Pinning the ordering here
34187        // means a future substrate-side tightening of either bound (a
34188        // K8s SIG-Network Hostname promotion narrowing the total cap, a
34189        // DNS-1123 label promotion widening the per-label cap) that
34190        // inverted the two would fail this pin at build time rather than
34191        // silently rendering the per-label arm unreachable.
34192        assert!(
34193            GATEWAY_API_HOSTNAME_MAX_LEN > DNS_1123_LABEL_MAX_LEN,
34194            "GATEWAY_API_HOSTNAME_MAX_LEN ({GATEWAY_API_HOSTNAME_MAX_LEN}) must strictly \
34195             exceed DNS_1123_LABEL_MAX_LEN ({DNS_1123_LABEL_MAX_LEN}) — every \
34196             `.`-separated label in a Gateway API v1 Hostname is itself a DNS-1123 \
34197             label under the apiserver's OpenAPI regex, so the total-length cap \
34198             must be able to accommodate at least one per-label-max label",
34199        );
34200    }
34201
34202    #[test]
34203    fn gateway_api_hostname_max_len_matches_rfc_1035_dns_name_limit() {
34204        // Cross-axis structural invariant: the Gateway API v1 Hostname
34205        // `maxLength: 253` cap is the RFC 1035 / RFC 1123 DNS name limit
34206        // — 255 wire bytes minus one length prefix minus the implicit
34207        // trailing dot — the same cap every DNS-compliant `HostName`
34208        // primitive downstream substrate consumer (the future
34209        // per-`Certificate` SAN emitter for cert-manager, the future
34210        // multi-`:entrada` host-collision gate) will inherit by
34211        // construction. Pinning the arithmetic here rather than the
34212        // literal `253` makes the RFC derivation explicit at the const's
34213        // test site so a future migration onto a different DNS-name
34214        // ceiling (an eventual RFC-successor limit, a per-cluster
34215        // override the operator pins) surfaces at this pin, not at every
34216        // downstream renderer's admission-rejection loop.
34217        assert_eq!(
34218            GATEWAY_API_HOSTNAME_MAX_LEN,
34219            255 - 1 - 1,
34220            "GATEWAY_API_HOSTNAME_MAX_LEN must equal the RFC 1035 / RFC 1123 DNS \
34221             name limit (255 wire bytes minus one length prefix minus the trailing \
34222             dot)",
34223        );
34224    }
34225
34226    #[test]
34227    fn gateway_api_default_http_listener_port_pins_canonical_80_literal() {
34228        // The canonical-constant arm — pins
34229        // [`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`] at the verbatim
34230        // `80` literal the sole `caixa-mesh::gateway_routes` per-
34231        // Aplicacao `Gateway` per-listener HTTP-listener-port axis
34232        // reads from. Peer with the
34233        // [`crate::DEFAULT_SERVICO_PORT`]-pins-`8080` discipline on the
34234        // sibling per-renderer canonical-K8s-port-axis typed `u16`
34235        // const: a future refactor that drifts the constant out from
34236        // under either consumer surfaces here ahead of any per-renderer
34237        // Gateway emission. The literal value is IANA's well-known
34238        // `http` service port (RFC 9110 §4.2.2), so an
34239        // `http://<entrada.host>/…` URL without a `:<port>` selector
34240        // reaches the listener by construction.
34241        assert_eq!(
34242            GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT, 80,
34243            "canonical Gateway API v1 HTTP listener port literal must remain \
34244             `80` verbatim — this is the value the caixa-mesh Gateway emitter \
34245             reads from and the IANA-registered well-known `http` service port"
34246        );
34247    }
34248
34249    #[test]
34250    fn gateway_api_default_http_listener_port_distinct_from_default_servico_port() {
34251        // Cross-axis structural invariant: the Gateway listener's
34252        // external HTTP port ([`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`],
34253        // 80) and the per-Servico in-cluster L4 port
34254        // ([`DEFAULT_SERVICO_PORT`], 8080) are two distinct axes — the
34255        // external-ingress port the K8s Gateway API controller opens on
34256        // the cluster boundary, and the internal-Servico port the
34257        // `pleme-computeunit` chart emits per Servico `Service`.
34258        // Collapsing the two would silently emit a Gateway whose
34259        // listener port matched the Servico's own port, so a stray
34260        // Servico exposing its Service directly to a cluster-external
34261        // LoadBalancer would shadow the Aplicacao's Gateway path — the
34262        // typed two-axis distinction guards against a rebrand on either
34263        // axis silently converging on the other's value. Peer with the
34264        // [`GATEWAY_API_HOSTNAME_MAX_LEN`]-strictly-exceeds-[`DNS_1123_LABEL_MAX_LEN`]
34265        // discipline on the sibling per-axis structural-ordering pin
34266        // set — both are cross-axis invariants between two lifted
34267        // constants that share a downstream renderer.
34268        assert_ne!(
34269            GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT,
34270            crate::DEFAULT_SERVICO_PORT,
34271            "GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT ({GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT}) \
34272             must remain distinct from DEFAULT_SERVICO_PORT ({}) — the two axes name \
34273             different scalars (external-Gateway listener port vs in-cluster Servico port), \
34274             collapsing them silently shadows the Aplicacao's Gateway path",
34275            crate::DEFAULT_SERVICO_PORT,
34276        );
34277    }
34278
34279    #[test]
34280    fn gateway_api_default_http_listener_name_pins_canonical_http_literal() {
34281        // The canonical-constant arm — pins
34282        // [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`] at the verbatim
34283        // `"http"` literal the sole `caixa-mesh::gateway_routes` per-
34284        // Aplicacao `Gateway` per-listener name-discriminator axis
34285        // reads from. Peer with the
34286        // [`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`]-pins-`80` discipline
34287        // on the sibling per-listener HTTP-listener-port scalar-axis:
34288        // both are the Aplicacao-side substrate-canonical scalar-value
34289        // pins the sole per-Aplicacao `Gateway` emitter reaches for, so
34290        // a future refactor that drifts either constant out from under
34291        // the emitter surfaces here ahead of any per-renderer Gateway
34292        // emission. The literal value is the substrate's V0 arbitrary-
34293        // author-chosen short listener-name (K8s Gateway API v1's
34294        // `SectionName`-typed field carries no CRD-schema-pinned value
34295        // — the substrate picks `"http"` verbatim to match the
34296        // listener's carried protocol shape at the reader's eye), so
34297        // downstream `HTTPRoute` `sectionName` selectors bind to this
34298        // exact byte-string by construction.
34299        assert_eq!(
34300            GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME, "http",
34301            "canonical Gateway API v1 HTTP listener-name literal must remain \
34302             `\"http\"` verbatim — this is the value the caixa-mesh Gateway \
34303             emitter reads from and the substrate's V0 arbitrary-author-chosen \
34304             short listener-name identifier every downstream `HTTPRoute` \
34305             `parentRefs[].sectionName` selector binds to"
34306        );
34307    }
34308
34309    #[test]
34310    fn gateway_api_default_http_listener_name_carries_dns_1123_label_shape() {
34311        // Cross-axis invariant: K8s Gateway API v1 `Listener.name` is
34312        // `SectionName`-typed — a required DNS-1123 label unique within
34313        // the parent Gateway's listener list. Pinning the shape here
34314        // means a future rebrand on the canonical lift can't silently
34315        // land a malformed listener-name identifier (empty, uppercase,
34316        // whitespace, `.` / `_` / non-alphanumeric characters, an
34317        // overlong string past the DNS-1123 label ceiling) that the
34318        // apiserver-side Gateway API CRD schema validator would reject
34319        // far from the rebrand commit's source. The predicate the
34320        // `caixa-mesh::gateway_routes` per-listener-name emitter never
34321        // consults directly (the value is a const — no author input
34322        // reaches this axis today) gets consulted here so any future
34323        // rebrand routes through the same DNS-1123-label admission
34324        // grammar every K8s CRD `name`-shaped axis carries. Peer to
34325        // `default_gateway_class_name_is_a_valid_dns_1123_label` on
34326        // the sibling per-Gateway `gatewayClassName` scalar-axis pin
34327        // and `default_namespace_is_a_valid_dns_1123_label` on the
34328        // canonical-K8s-namespace lifted scalar — every substrate-side
34329        // K8s-CRD-name-shaped lift carries the same DNS-1123 label
34330        // admission-grammar cross-axis invariant.
34331        assert!(
34332            is_dns_1123_label(GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME).is_ok(),
34333            "GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME ({GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME:?}) \
34334             must be a valid DNS-1123 label — K8s Gateway API v1 `Listener.name` is \
34335             `SectionName`-typed and the apiserver-side CRD schema validator refuses \
34336             any other shape"
34337        );
34338    }
34339
34340    #[test]
34341    fn gateway_api_default_http_route_path_pins_canonical_root_literal() {
34342        // The canonical-constant arm — pins
34343        // [`GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH`] at the verbatim `"/"`
34344        // literal the sole `caixa-mesh::gateway_routes` per-Aplicacao
34345        // `HTTPRoute` empty-`:entrada :paths` catch-all URL-path
34346        // resolver reads from. Peer with the
34347        // [`GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME`]-pins-`"http"` and
34348        // [`GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT`]-pins-`80`
34349        // disciplines on the sibling per-listener substrate-canonical
34350        // scalar-value axes: all three are the Aplicacao-side
34351        // substrate-canonical scalar-value pins the sole per-Aplicacao
34352        // Gateway API v1 CRD emitter reaches for, so a future refactor
34353        // that drifts any one constant out from under the emitter
34354        // surfaces here ahead of any per-renderer HTTPRoute emission.
34355        // The literal value is the K8s Gateway API v1 canonical
34356        // catch-all shape: `PathPrefix "/"` — the upstream docs at
34357        // <https://gateway-api.sigs.k8s.io/api-types/httproute/#path-based-routing>
34358        // pin the bare-root byte-string as the "match anything the
34359        // listener admits" idiom every gateway-class controller treats
34360        // as the equivalent of "no path predicate".
34361        assert_eq!(
34362            GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH, "/",
34363            "canonical Gateway API v1 HTTPRoute catch-all path literal must remain \
34364             `\"/\"` verbatim — this is the value the caixa-mesh HTTPRoute emitter \
34365             renders whenever the typed `:entrada :paths` list is empty and every \
34366             gateway-class controller (Cilium's Envoy, Envoy Gateway, Istio Gateway) \
34367             treats as the canonical `PathPrefix` catch-all"
34368        );
34369    }
34370
34371    #[test]
34372    fn gateway_api_default_http_route_path_carries_valid_gateway_api_http_path_shape() {
34373        // Cross-axis invariant: K8s Gateway API v1
34374        // `HTTPPathMatch.value` is admitted by the apiserver-side CRD
34375        // schema regex the substrate mirrors in the shared
34376        // [`is_gateway_api_http_path`] predicate — the same admission
34377        // grammar every author-supplied [`crate::aplicacao::Entrada`]
34378        // `:paths` entry clears at typed-validate time. Pinning the
34379        // shape here means a future rebrand on the canonical lift can't
34380        // silently land a malformed catch-all URL-path scalar (empty,
34381        // no leading `/`, overlong past the K8s Gateway API v1
34382        // `HTTPPathMatch.value` ceiling, `..`-segment-bearing, ASCII-
34383        // control-bearing, non-ASCII-bearing) that the apiserver-side
34384        // Gateway API CRD schema validator would reject far from the
34385        // rebrand commit's source. The paired
34386        // [`caixa_mesh::gateway_routes`] emitter never consults the
34387        // predicate directly (the catch-all value is a const — no
34388        // author input reaches this axis today) so consulting it here
34389        // means any future rebrand routes through the same
34390        // admission-grammar the peer author-side
34391        // `:entrada :paths` slot's `AplicacaoSpec::validate` gate
34392        // carries. Peer to
34393        // `gateway_api_default_http_listener_name_carries_dns_1123_label_shape`
34394        // on the sibling per-listener name-scalar cross-axis invariant
34395        // — every substrate-side Gateway-API-scalar lift carries the
34396        // matching per-axis admission-grammar cross-axis pin.
34397        assert!(
34398            is_gateway_api_http_path(GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH).is_ok(),
34399            "GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH ({GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH:?}) \
34400             must clear the shared HTTP-path admission grammar — K8s Gateway API v1 \
34401             `HTTPPathMatch.value` is CRD-schema-regex-validated and the apiserver-side \
34402             schema validator refuses any other shape at apply time"
34403        );
34404    }
34405
34406    // ── insert_first_seen ───────────────────────────────────────────────
34407
34408    #[derive(Debug, PartialEq, Eq)]
34409    enum DupTestErr {
34410        Dup(&'static str),
34411    }
34412
34413    #[test]
34414    fn insert_first_seen_accepts_distinct_keys_without_firing_closure() {
34415        // The happy path — every distinct key returns `Ok(())` and the
34416        // caller's `on_duplicate` closure is never invoked. Pins the
34417        // `HashSet::insert`-returning-`true`-on-first-insertion contract
34418        // the ten consumer sites (`:membros`, `:placement :clusters`,
34419        // `:entrada :paths`, `:contratos`, `:children`, `:deps`,
34420        // `:deps-dev`, `:etiquetas`, `:autores`, `:caracteristicas`,
34421        // code-paths) each rely on — a future refactor that flips the
34422        // sense of the delegated `insert` return would surface here
34423        // ahead of every per-consumer duplicate arm silently mis-firing
34424        // on distinct keys.
34425        let mut seen: std::collections::HashSet<&str> = std::collections::HashSet::new();
34426        for key in ["cart", "catalog", "payment"] {
34427            assert_eq!(
34428                insert_first_seen::<&str, DupTestErr, _>(&mut seen, key, || DupTestErr::Dup(
34429                    "must not fire"
34430                )),
34431                Ok(()),
34432                "first insertion of {key:?} must return Ok(())",
34433            );
34434        }
34435        assert_eq!(seen.len(), 3, "every distinct key must land in the set");
34436    }
34437
34438    #[test]
34439    fn insert_first_seen_surfaces_caller_shaped_error_on_second_insertion() {
34440        // The duplicate arm — the second occurrence of any key surfaces
34441        // the caller's `on_duplicate` return verbatim. Pins the
34442        // "declaration-order-preserving first-collision" discipline every
34443        // peer `Duplicate*` variant documents: the first colliding entry
34444        // reports, not the last. Same shape the ten consumer sites'
34445        // `*_duplicate_diagnostic_names_second_collision` posture tests
34446        // pin at the caller layer; this lift makes the sequencing a
34447        // property of the helper, not a per-call-site convention.
34448        let mut seen: std::collections::HashSet<&str> = std::collections::HashSet::new();
34449        assert_eq!(
34450            insert_first_seen::<&str, DupTestErr, _>(&mut seen, "cart", || DupTestErr::Dup(
34451                "first"
34452            )),
34453            Ok(()),
34454            "first insertion must Ok",
34455        );
34456        assert_eq!(
34457            insert_first_seen::<&str, DupTestErr, _>(&mut seen, "cart", || DupTestErr::Dup(
34458                "second"
34459            )),
34460            Err(DupTestErr::Dup("second")),
34461            "second insertion must fire the caller's closure with its own tag",
34462        );
34463    }
34464
34465    #[test]
34466    fn insert_first_seen_generic_over_tuple_key_used_by_contratos_gate() {
34467        // The [`crate::AplicacaoSpec::validate`] `:contratos` gate carries
34468        // a six-tuple typed-edge identity key
34469        // (`(de, para, wit, endpoint, subject, slot)`) — the only non-
34470        // `&str` key shape in the crate's per-list uniqueness set. Pin
34471        // the generic-over-`K` contract here so a future refactor that
34472        // narrows the helper to `&str`-only keys (a hypothetical
34473        // `HashSet<&str>`-specialized rewrite) surfaces at this pin
34474        // rather than as a compile error at the sole tuple-carrying
34475        // consumer. The tuple set here mirrors the shape
34476        // `ContratoIdentity` carries.
34477        let mut seen: std::collections::HashSet<(&str, &str, &str, Option<&str>)> =
34478            std::collections::HashSet::new();
34479        let key = ("cart", "catalog", "wasi:http/proxy", Some("/products"));
34480        assert_eq!(
34481            insert_first_seen::<_, DupTestErr, _>(&mut seen, key, || DupTestErr::Dup(
34482                "must not fire"
34483            )),
34484            Ok(()),
34485        );
34486        assert_eq!(
34487            insert_first_seen::<_, DupTestErr, _>(&mut seen, key, || DupTestErr::Dup("collision")),
34488            Err(DupTestErr::Dup("collision")),
34489            "identical tuple key on second insertion must fire the duplicate arm",
34490        );
34491    }
34492
34493    // ── assert_str_reexport_identity ──────────────────────────────────
34494
34495    #[test]
34496    fn assert_str_reexport_identity_accepts_same_static_allocation() {
34497        // Positive path — passing the same `&'static str` twice (the
34498        // shape a `pub use caixa_core::X;` re-export produces at every
34499        // consumer site) must not panic. This is the ~75-caller-site
34500        // happy path that the lifted test-side pin gate collapses onto.
34501        // The compiler-interned literal `"KUBE_KEY_SPEC"` reaches this
34502        // helper twice through the same `&'static` allocation, so
34503        // `std::ptr::eq(a.as_ptr(), b.as_ptr())` returns true and the
34504        // second `assert!` arm passes without firing.
34505        const CANONICAL: &str = "canonical-value";
34506        assert_str_reexport_identity("CANONICAL_UNDER_TEST", CANONICAL, CANONICAL);
34507    }
34508
34509    #[test]
34510    #[should_panic(
34511        expected = "SIBLING_UNDER_TEST must be a re-export of caixa_core::SIBLING_UNDER_TEST"
34512    )]
34513    fn assert_str_reexport_identity_rejects_sibling_allocation_with_same_bytes() {
34514        // Negative path — passing two byte-equal `&'static str`s whose
34515        // underlying allocations differ (the shape a sibling `pub const
34516        // X: &str = "…"` at a renderer crate produces, silently carrying
34517        // the same bytes but its own `&'static` allocation) must panic
34518        // on the [`std::ptr::eq`] arm, naming the offending re-export.
34519        // Reproduces the canonical drift footgun the lift closes: byte-
34520        // equality via [`assert_eq!`] alone silently admits the drift
34521        // — the two strings are equal — but the allocation-identity
34522        // arm catches it structurally. Uses [`String::leak`] to
34523        // materialize a fresh `&'static str` allocation carrying the
34524        // same bytes as the compiler-interned canonical literal, so
34525        // the two share bytes but differ in allocation.
34526        const CANONICAL: &str = "canonical-value";
34527        let sibling: &'static str = String::from("canonical-value").leak();
34528        // Sanity — the sibling and canonical share bytes …
34529        assert_eq!(sibling, CANONICAL);
34530        // … but must live at distinct `&'static` allocations for this
34531        // negative path to fire on the identity arm rather than
34532        // silently pass on the equality arm.
34533        assert!(!std::ptr::eq(sibling.as_ptr(), CANONICAL.as_ptr()));
34534        assert_str_reexport_identity("SIBLING_UNDER_TEST", sibling, CANONICAL);
34535    }
34536
34537    #[test]
34538    #[should_panic(expected = "DRIFTED_UNDER_TEST must byte-equal caixa_core::DRIFTED_UNDER_TEST")]
34539    fn assert_str_reexport_identity_rejects_bytes_drift_before_identity_arm() {
34540        // Ordering pin — when the two byte-strings differ, the
34541        // [`assert_eq!`] arm must fire *before* the [`std::ptr::eq`]
34542        // identity arm reaches for `.as_ptr()`. Pins the arm sequencing
34543        // so a future refactor that flipped the two arms (identity
34544        // first, byte-equality second) would surface here rather than
34545        // report the wrong diagnostic against a drifted canonical
34546        // (the byte-equality diagnostic self-locates the value drift;
34547        // the identity diagnostic self-locates the allocation drift —
34548        // reporting the identity arm on a value-drifted pair points
34549        // the reader at the wrong failure class). Same discipline as
34550        // the peer `require_positive_canonical_bounded_duration`
34551        // three-arm-ordering pin above.
34552        const CANONICAL: &str = "canonical-value";
34553        const DRIFTED: &str = "drifted-value";
34554        assert_str_reexport_identity("DRIFTED_UNDER_TEST", DRIFTED, CANONICAL);
34555    }
34556
34557    #[test]
34558    fn computeunit_spec_key_module_pins_canonical_value() {
34559        // Pin the actual byte-string so a typo in this lift can't silently
34560        // rebrand the `wasm.pleme.io/v1alpha1/ComputeUnit` CRD per-CR
34561        // `spec.module` sub-block key both caixa-flux and caixa-helm
34562        // navigate to reach the per-Servico wasm-component reference the
34563        // M2.5 wasm-engine instantiator loads at Servico bring-up. The
34564        // value is part of the cluster-side contract with the
34565        // `pleme-computeunit` library chart's per-values module-source
34566        // routing + the `caixa-operator` `ComputeUnit` CR admission
34567        // webhook's per-CR module-reference resolver; changing it is a
34568        // coordinated ComputeUnit-CRD schema migration alongside the
34569        // upstream substrate release, not an incidental edit. Peer to
34570        // `default_namespace_pins_canonical_value` /
34571        // `helm_values_yaml_filename_pins_canonical_value` /
34572        // `helm_chart_yaml_filename_pins_canonical_value` on the sibling
34573        // canonical-substrate-schema-key axes.
34574        assert_eq!(COMPUTEUNIT_SPEC_KEY_MODULE, "module");
34575    }
34576
34577    #[test]
34578    fn computeunit_spec_key_trigger_pins_canonical_value() {
34579        // Peer to `computeunit_spec_key_module_pins_canonical_value` on
34580        // the same ComputeUnit-CRD per-`spec.*` sub-block axis — pins
34581        // the per-CR invocation-shape sub-block key every
34582        // `pleme-computeunit`-library-chart-driven per-Servico
34583        // `trigger.service.port` / `trigger.service.paths` /
34584        // `trigger.service.breathability` values-block route reads back.
34585        assert_eq!(COMPUTEUNIT_SPEC_KEY_TRIGGER, "trigger");
34586    }
34587
34588    #[test]
34589    fn computeunit_spec_key_capabilities_pins_canonical_value() {
34590        // Peer to `computeunit_spec_key_module_pins_canonical_value` and
34591        // `computeunit_spec_key_trigger_pins_canonical_value` on the same
34592        // ComputeUnit-CRD per-`spec.*` sub-block axis — pins the per-CR
34593        // WASI-capability-token-list sub-block key the M2.5 wasm-engine
34594        // instantiator reads to bind the per-component capability set
34595        // (WASI-preview-2 preview-interfaces per the WIT Component Model)
34596        // at Servico bring-up.
34597        assert_eq!(COMPUTEUNIT_SPEC_KEY_CAPABILITIES, "capabilities");
34598    }
34599
34600    #[test]
34601    fn computeunit_spec_keys_carry_lowercase_shape() {
34602        // Cross-axis invariant: every `wasm.pleme.io/v1alpha1/ComputeUnit`
34603        // CRD per-`spec.*` sub-block key is all-ASCII-lowercase
34604        // throughout — the ComputeUnit CRD's schema convention on the
34605        // per-`spec.*` sub-block axis. A drifted UpperCamelCase /
34606        // hyphenated variant (`"Module"` / `"module-source"` /
34607        // `"Trigger"` / `"Capabilities"` — the OpenAPI-CRD-schema
34608        // canonical-form footgun the peer `KUBE_KEY_*` axes share) would
34609        // land the emit-side key outside the CRD's admitted per-sub-
34610        // block set and the `caixa-operator` admission webhook would
34611        // silently drop the per-Servico wasm-runtime binding — the
34612        // Servico pods would come up under the library-chart defaults
34613        // (no module bound, no trigger bound, no capability set)
34614        // instead of the caixa.lisp's declared per-`:servicos` axis.
34615        // Same all-ASCII-lowercase shape gate as the peer M2 typed-slot
34616        // camelCase-key axes ([`M2_KEY_LIMITS`] / [`M2_KEY_BEHAVIOR`] —
34617        // the compound-word slot [`M2_KEY_UPGRADE_FROM`] adds a
34618        // camelHump per its `#[serde(rename_all = "camelCase")]`-derived
34619        // shape, but the leading-word gate is the same).
34620        for k in [
34621            COMPUTEUNIT_SPEC_KEY_MODULE,
34622            COMPUTEUNIT_SPEC_KEY_TRIGGER,
34623            COMPUTEUNIT_SPEC_KEY_CAPABILITIES,
34624        ] {
34625            assert!(
34626                k.bytes().all(|b| b.is_ascii_lowercase()),
34627                "ComputeUnit CRD per-`spec.*` sub-block key {k:?} must be \
34628                 all-ASCII-lowercase per the CRD schema convention"
34629            );
34630        }
34631    }
34632
34633    #[test]
34634    fn computeunit_spec_keys_appear_verbatim_in_sample_computeunit_yaml() {
34635        // Round-trip pin: the exact byte-strings the three lifted
34636        // constants carry appear verbatim as the top-level `spec.*`
34637        // sub-block keys of a canonical in-tree `ComputeUnit` YAML —
34638        // the same shape [`caixa_flux::programs_yaml_entry`] and
34639        // [`caixa_helm::build_values_yaml`] consume via
34640        // `serde_yaml::from_str`. Pins the const-to-schema round-trip
34641        // so a future ComputeUnit-CRD schema rebrand (a `binary:` /
34642        // `component:` / `invoke:` / `caps:` / `spec.wasm.*` axis
34643        // rename the ABSORPTION-ROADMAP.md M4-M5 trajectory names)
34644        // surfaces here as a build error rather than as a silent
34645        // per-Servico wasm-runtime-binding drop at cluster-apply time.
34646        let cu: serde_yaml::Value = serde_yaml::from_str(
34647            r#"
34648apiVersion: wasm.pleme.io/v1alpha1
34649kind: ComputeUnit
34650metadata:
34651  name: hello-rio
34652spec:
34653  module:
34654    source: oci://ghcr.io/pleme-io/hello-rio:v0.1.0
34655  trigger:
34656    service:
34657      port: 8080
34658      paths: ["/"]
34659  capabilities:
34660    - env
34661"#,
34662        )
34663        .unwrap();
34664        let spec = cu.get(KUBE_KEY_SPEC).expect("spec key present");
34665        assert!(
34666            spec.get(COMPUTEUNIT_SPEC_KEY_MODULE).is_some(),
34667            "spec.{COMPUTEUNIT_SPEC_KEY_MODULE} sub-block must be present"
34668        );
34669        assert!(
34670            spec.get(COMPUTEUNIT_SPEC_KEY_TRIGGER).is_some(),
34671            "spec.{COMPUTEUNIT_SPEC_KEY_TRIGGER} sub-block must be present"
34672        );
34673        assert!(
34674            spec.get(COMPUTEUNIT_SPEC_KEY_CAPABILITIES).is_some(),
34675            "spec.{COMPUTEUNIT_SPEC_KEY_CAPABILITIES} sub-block must be present"
34676        );
34677        // Nested `spec.module.source` leaf-scalar sub-block: every
34678        // rendered ComputeUnit YAML declares the wasm-component
34679        // reference under this leaf, and every downstream
34680        // `programs[].module.source` readback the
34681        // [`caixa_flux::programs_yaml_entry`] round-trip pins reaches
34682        // for the same `&'static str`. Peer to the top-level
34683        // `spec.{module,trigger,capabilities}` presence assertions
34684        // above — extends the round-trip pin one level deeper onto
34685        // the module-block's leaf reference-value axis.
34686        let module = spec
34687            .get(COMPUTEUNIT_SPEC_KEY_MODULE)
34688            .expect("spec.module block present");
34689        assert!(
34690            module.get(COMPUTEUNIT_MODULE_KEY_SOURCE).is_some(),
34691            "spec.{COMPUTEUNIT_SPEC_KEY_MODULE}.{COMPUTEUNIT_MODULE_KEY_SOURCE} \
34692             leaf-scalar sub-block must be present"
34693        );
34694        assert_eq!(
34695            module
34696                .get(COMPUTEUNIT_MODULE_KEY_SOURCE)
34697                .and_then(|s| s.as_str()),
34698            Some("oci://ghcr.io/pleme-io/hello-rio:v0.1.0"),
34699            "the ComputeUnit CRD per-`module.source` axis carries the wasm-\
34700             component OCI/git reference verbatim"
34701        );
34702    }
34703
34704    #[test]
34705    fn computeunit_module_key_source_pins_canonical_value() {
34706        // Peer to `computeunit_spec_key_module_pins_canonical_value` on
34707        // the nested `spec.module.*` sub-block axis — pins the per-CR
34708        // wasm-component-reference leaf-scalar key every
34709        // [`caixa_flux::programs_yaml_entry`] round-trip navigator and
34710        // every [`caixa_flux::upsert_into_programs_yaml`] /
34711        // [`caixa_flux::upsert_into_helmrelease_programs`] cross-
34712        // upsert readback resolves under the parent
34713        // `COMPUTEUNIT_SPEC_KEY_MODULE`. Changing this value is a
34714        // coordinated ComputeUnit-CRD schema migration alongside the
34715        // `pleme-computeunit` library chart's per-values module-source
34716        // routing + the `caixa-operator` `ComputeUnit` CR admission
34717        // webhook's per-CR module-reference resolver, not an
34718        // incidental edit.
34719        assert_eq!(COMPUTEUNIT_MODULE_KEY_SOURCE, "source");
34720    }
34721
34722    #[test]
34723    fn computeunit_module_key_source_carries_lowercase_shape() {
34724        // Cross-axis invariant: the nested `spec.module.*` leaf-scalar
34725        // sub-block key is all-ASCII-lowercase throughout — the
34726        // ComputeUnit CRD's schema convention on the per-`spec.module.*`
34727        // leaf axis, same as the top-level per-`spec.*` sub-block
34728        // axis the sibling `COMPUTEUNIT_SPEC_KEY_*` peers gate.
34729        // A drifted UpperCamelCase / hyphenated variant (`"Source"` /
34730        // `"module-source"` / `"src"` — the OpenAPI-CRD-schema
34731        // canonical-form footgun the peer `KUBE_KEY_*` axes share)
34732        // would land the emit-side key outside the CRD's admitted
34733        // per-`module.*` set and the `caixa-operator` admission
34734        // webhook would silently drop the per-Servico wasm-module
34735        // reference — the Servico pods would come up under the
34736        // library-chart defaults (no module bound) instead of the
34737        // caixa.lisp's declared per-`:servicos` axis. Same all-ASCII-
34738        // lowercase shape gate as the peer `COMPUTEUNIT_SPEC_KEY_*`
34739        // top-level axes.
34740        assert!(
34741            COMPUTEUNIT_MODULE_KEY_SOURCE
34742                .bytes()
34743                .all(|b| b.is_ascii_lowercase()),
34744            "ComputeUnit CRD per-`spec.module.*` leaf-scalar sub-block key \
34745             {COMPUTEUNIT_MODULE_KEY_SOURCE:?} must be all-ASCII-lowercase \
34746             per the CRD schema convention"
34747        );
34748    }
34749
34750    #[test]
34751    fn mapping_ext_insert_str_key_promotes_key_to_yaml_string() {
34752        // The trait method promotes an arbitrary `&str` key to
34753        // `Value::String(key.to_string())` — pin the promotion so a
34754        // future refactor that reaches for a different `Value` variant
34755        // for the key (e.g. `Value::Tagged`) is a compile-visible break,
34756        // not a silent per-consumer regression at the K8s-artifact-emit
34757        // surface.
34758        let mut m = serde_yaml::Mapping::new();
34759        let prior = m.insert_str_key("spec", serde_yaml::Value::Bool(true));
34760        assert!(
34761            prior.is_none(),
34762            "insert_str_key returns None on first insertion, mirroring \
34763             serde_yaml::Mapping::insert"
34764        );
34765        // Key is exactly the `Value::String` promotion of the input.
34766        let got = m
34767            .get(serde_yaml::Value::String("spec".to_string()))
34768            .expect("inserted key is present under Value::String promotion");
34769        assert_eq!(
34770            got,
34771            &serde_yaml::Value::Bool(true),
34772            "insert_str_key routes value verbatim to the underlying \
34773             serde_yaml::Mapping::insert"
34774        );
34775    }
34776
34777    #[test]
34778    fn mapping_ext_insert_str_key_returns_prior_value_on_replace() {
34779        // The trait method mirrors [`serde_yaml::Mapping::insert`]'s
34780        // return contract: the prior value at that key, or `None` if
34781        // absent. Pin the replace-returns-prior semantic so a future
34782        // refactor that swaps to a `HashMap::entry`-style flow doesn't
34783        // silently drop the prior-value handoff downstream consumers may
34784        // reach for (the M4 per-`:politicas` overlay merger, the future
34785        // `feira app deploy` idempotent-write dry-run comparator).
34786        let mut m = serde_yaml::Mapping::new();
34787        m.insert_str_key("kind", serde_yaml::Value::String("Gateway".into()));
34788        let prior = m.insert_str_key("kind", serde_yaml::Value::String("HTTPRoute".into()));
34789        assert_eq!(
34790            prior,
34791            Some(serde_yaml::Value::String("Gateway".into())),
34792            "insert_str_key returns the prior value when replacing an existing key"
34793        );
34794        let got = m
34795            .get(serde_yaml::Value::String("kind".to_string()))
34796            .expect("key is still present after replace");
34797        assert_eq!(
34798            got,
34799            &serde_yaml::Value::String("HTTPRoute".into()),
34800            "replaced value is now the most-recently-inserted one"
34801        );
34802    }
34803
34804    #[test]
34805    fn mapping_ext_insert_str_key_matches_hand_written_promotion() {
34806        // Cross-check the trait method against the hand-written
34807        // `mapping.insert(Value::String(key.into()), value)` shape the
34808        // ~48 lifted call sites previously carried. A drift between the
34809        // trait method's promotion and the inline promotion the prior
34810        // call sites used would silently emit a different YAML mapping
34811        // (a differently-quoted key, a different `Value` variant) at
34812        // every routed consumer — pin the equivalence so the trait
34813        // remains a drop-in replacement.
34814        let mut via_trait = serde_yaml::Mapping::new();
34815        via_trait.insert_str_key(KUBE_KEY_KIND, serde_yaml::Value::String("Gateway".into()));
34816
34817        let mut via_inline = serde_yaml::Mapping::new();
34818        via_inline.insert(
34819            serde_yaml::Value::String(KUBE_KEY_KIND.into()),
34820            serde_yaml::Value::String("Gateway".into()),
34821        );
34822
34823        assert_eq!(
34824            via_trait, via_inline,
34825            "insert_str_key(KEY, V) must byte-equal \
34826             insert(Value::String(KEY.into()), V) — otherwise the \
34827             ~48 routed consumer sites drift silently at emit time"
34828        );
34829    }
34830
34831    #[test]
34832    fn mapping_get_bare_str_key_byte_equals_value_string_wrapped_form() {
34833        // The read-side twin of the `insert_str_key`-vs-hand-written pin.
34834        // `serde_yaml::Mapping::get<I: Index>` accepts any `I: Index`;
34835        // the crate ships `impl Index for str` (routing through a
34836        // no-allocation `HashLikeValue(&str)` bucket lookup) and
34837        // `impl Index for Value` (matching the `Value::String(_)`
34838        // key verbatim). The ~78 test-side probes across `caixa-mesh`,
34839        // `caixa-flux`, and `caixa-core::render` that previously spelled
34840        // out `.get(serde_yaml::Value::String(<KEY>.into()))` were
34841        // swept onto the shorter `.get(<KEY>)` form because the two
34842        // must resolve to the same bucket for the sweep to be a
34843        // drop-in. Pin the equivalence — the `HashLikeValue(&str)`
34844        // hash must byte-equal the `Value::String(String)` hash so
34845        // the two paths agree on `get`, `contains_key`, and the
34846        // absence path (`None` when the key is missing) — otherwise
34847        // a future `serde_yaml` upgrade could silently divert every
34848        // swept probe past the value the emitter inserted.
34849        let mut m = serde_yaml::Mapping::new();
34850        m.insert_str_key(KUBE_KEY_KIND, serde_yaml::Value::String("Gateway".into()));
34851        // Present-key path: both forms find the same value.
34852        assert_eq!(
34853            m.get(KUBE_KEY_KIND),
34854            m.get(serde_yaml::Value::String(KUBE_KEY_KIND.into())),
34855            "mapping.get(<KEY>) must byte-equal \
34856             mapping.get(Value::String(<KEY>.into())) — otherwise the \
34857             ~78 swept test-side probes drift silently past the value \
34858             the emitter inserted under the promoted Value::String key"
34859        );
34860        // Absent-key path: both forms return None.
34861        assert_eq!(
34862            m.get(KUBE_KEY_SPEC),
34863            m.get(serde_yaml::Value::String(KUBE_KEY_SPEC.into())),
34864            "absent-key lookup via bare-&str must byte-equal absent-key \
34865             lookup via Value::String — both must return None so the \
34866             swept `assert!(_.get(K).is_none())` shape stays load-bearing"
34867        );
34868        // contains_key parity: both forms agree on present + absent.
34869        assert_eq!(
34870            m.contains_key(KUBE_KEY_KIND),
34871            m.contains_key(serde_yaml::Value::String(KUBE_KEY_KIND.into())),
34872            "mapping.contains_key(<KEY>) must byte-equal \
34873             mapping.contains_key(Value::String(<KEY>.into())) — \
34874             otherwise the swept `assert!(_.contains_key(K))` shape \
34875             disagrees with the emitter's `insert_str_key` promotion"
34876        );
34877        assert_eq!(
34878            m.contains_key(KUBE_KEY_SPEC),
34879            m.contains_key(serde_yaml::Value::String(KUBE_KEY_SPEC.into())),
34880            "absent-key contains_key via bare-&str must byte-equal \
34881             absent-key contains_key via Value::String"
34882        );
34883    }
34884
34885    #[test]
34886    fn mapping_get_mut_bare_str_key_byte_equals_value_string_wrapped_form() {
34887        // The mutation-path twin of the read-side pin above.
34888        // `serde_yaml::Mapping::get_mut<I: Index>` accepts any
34889        // `I: Index` — the crate ships `impl Index for str` (routing
34890        // through the same no-allocation `HashLikeValue(&str)` bucket
34891        // lookup the read-side `get` / `contains_key` sweep landed on
34892        // in 0e84fb9) and `impl Index for Value` (matching the
34893        // `Value::String(_)` key verbatim). Until this pin landed the
34894        // sole production `.get_mut(serde_yaml::Value::String(<KEY>.into()))`
34895        // probe — [`caixa_flux::upsert_into_helmrelease_programs`]'s
34896        // `root.get_mut(…)` HelmRelease-side spec-mutate at
34897        // `caixa-flux/src/lib.rs:845` (which the sibling
34898        // `kube_key_spec_re_export_points_at_caixa_core_canonical`
34899        // pinning test's docstring already described in the shorter
34900        // `root.get_mut("spec")` form the 0e84fb9 read-side sweep
34901        // landed elsewhere on) — carried the verbose `Value::String`-
34902        // wrapped shape as the last stray hold-out on the `get_mut`
34903        // axis. The sweep swaps it onto the bare-`&str` form, matching
34904        // the ~78 read-side probes 0e84fb9 already swept and the
34905        // in-file `kube_key_spec_re_export_points_at_caixa_core_canonical`
34906        // docstring's canonical description. Pin the equivalence — the
34907        // `HashLikeValue(&str)` hash must byte-equal the
34908        // `Value::String(String)` hash so the two paths agree on both
34909        // the present-key path (returns `Some(&mut _)` at the same
34910        // slot) and the absent-key path (returns `None` when the key
34911        // is missing) — otherwise a future `serde_yaml` upgrade could
34912        // silently divert the writer-side upsert past the value the
34913        // emitter previously mutated. Peer to the read-side
34914        // [`mapping_get_bare_str_key_byte_equals_value_string_wrapped_form`]
34915        // pin on the sibling `get` / `contains_key` axes; together the
34916        // two pins pin every `Index`-polymorphic probe axis the
34917        // caixa-flux upsert path walks.
34918        let mut m = serde_yaml::Mapping::new();
34919        m.insert_str_key(KUBE_KEY_KIND, serde_yaml::Value::String("Gateway".into()));
34920        // Present-key path: both forms find the same slot.
34921        // Cross-check by mutating through the bare-&str path and
34922        // observing the mutation via the Value::String path (and vice
34923        // versa) — anything short of exact bucket-equality would
34924        // silently split the two probes onto different slots.
34925        {
34926            let via_bare = m
34927                .get_mut(KUBE_KEY_KIND)
34928                .expect("present key must resolve via bare-&str");
34929            *via_bare = serde_yaml::Value::String("HTTPRoute".into());
34930        }
34931        assert_eq!(
34932            m.get(serde_yaml::Value::String(KUBE_KEY_KIND.into())),
34933            Some(&serde_yaml::Value::String("HTTPRoute".into())),
34934            "mutation via mapping.get_mut(<KEY>) must be visible via \
34935             mapping.get(Value::String(<KEY>.into())) — otherwise the \
34936             swept `get_mut` writer-side probe drifts past the value \
34937             the emitter reads through the promoted Value::String key"
34938        );
34939        {
34940            let via_wrapped = m
34941                .get_mut(serde_yaml::Value::String(KUBE_KEY_KIND.into()))
34942                .expect("present key must also resolve via Value::String");
34943            *via_wrapped = serde_yaml::Value::String("Gateway".into());
34944        }
34945        assert_eq!(
34946            m.get(KUBE_KEY_KIND),
34947            Some(&serde_yaml::Value::String("Gateway".into())),
34948            "mutation via mapping.get_mut(Value::String(<KEY>.into())) \
34949             must be visible via mapping.get(<KEY>) — the two paths \
34950             address the same bucket in both directions"
34951        );
34952        // Absent-key path: both forms return None so the sole swept
34953        // `.get_mut(<KEY>).ok_or(Error::MissingField(<KEY>))` shape
34954        // stays load-bearing.
34955        assert!(
34956            m.get_mut(KUBE_KEY_SPEC).is_none(),
34957            "absent-key mapping.get_mut(<KEY>) must return None"
34958        );
34959        assert!(
34960            m.get_mut(serde_yaml::Value::String(KUBE_KEY_SPEC.into()))
34961                .is_none(),
34962            "absent-key mapping.get_mut(Value::String(<KEY>.into())) \
34963             must also return None — the two forms must agree on \
34964             absence so the swept `.ok_or(Error::MissingField(<KEY>))` \
34965             diagnostic still fires on a missing spec block"
34966        );
34967    }
34968
34969    #[test]
34970    fn mapping_ext_insert_string_promotes_value_to_yaml_string() {
34971        // The trait method promotes an arbitrary `Into<String>` value
34972        // to `Value::String(value.into())` — pin the promotion so a
34973        // future refactor that reaches for a different `Value` variant
34974        // for the string-scalar payload (e.g. `Value::Tagged` under a
34975        // K8s Server-Side-Apply typed-field-ownership axis rebrand) is
34976        // a compile-visible break, not a silent per-consumer regression
34977        // at the K8s-artifact-emit surface. Peer with
34978        // [`mapping_ext_insert_str_key_promotes_key_to_yaml_string`] on
34979        // the sibling `insert_str_key` primitive's key-promotion pin.
34980        let mut m = serde_yaml::Mapping::new();
34981        let prior = m.insert_string("kind", "Gateway");
34982        assert!(
34983            prior.is_none(),
34984            "insert_string returns None on first insertion, mirroring \
34985             serde_yaml::Mapping::insert"
34986        );
34987        let got = m
34988            .get("kind")
34989            .expect("inserted key is present under Value::String promotion");
34990        assert_eq!(
34991            got,
34992            &serde_yaml::Value::String("Gateway".into()),
34993            "insert_string routes value verbatim through Value::String \
34994             promotion"
34995        );
34996    }
34997
34998    #[test]
34999    fn mapping_ext_insert_string_returns_prior_value_on_replace() {
35000        // The trait method mirrors [`serde_yaml::Mapping::insert`]'s
35001        // return contract: the prior value at that key, or `None` if
35002        // absent. Pin the replace-returns-prior semantic so a future
35003        // refactor that swaps to a `HashMap::entry`-style flow doesn't
35004        // silently drop the prior-value handoff downstream consumers
35005        // may reach for. Peer with
35006        // [`mapping_ext_insert_str_key_returns_prior_value_on_replace`]
35007        // on the sibling `insert_str_key` primitive's replace-semantics
35008        // pin.
35009        let mut m = serde_yaml::Mapping::new();
35010        m.insert_string(KUBE_KEY_KIND, "Gateway");
35011        let prior = m.insert_string(KUBE_KEY_KIND, "HTTPRoute");
35012        assert_eq!(
35013            prior,
35014            Some(serde_yaml::Value::String("Gateway".into())),
35015            "insert_string returns the prior value when replacing an \
35016             existing key"
35017        );
35018        let got = m
35019            .get(KUBE_KEY_KIND)
35020            .expect("key is still present after replace");
35021        assert_eq!(
35022            got,
35023            &serde_yaml::Value::String("HTTPRoute".into()),
35024            "replaced value is now the most-recently-inserted one"
35025        );
35026    }
35027
35028    #[test]
35029    fn mapping_ext_insert_string_matches_hand_written_promotion() {
35030        // Cross-check the trait method against the hand-written
35031        // `mapping.insert_str_key(KEY, Value::String(V.into()))` shape
35032        // the ~17 lifted call sites previously carried. A drift between
35033        // the trait method's promotion and the inline promotion would
35034        // silently emit a different YAML mapping (a differently-quoted
35035        // scalar, a different `Value` variant) at every routed
35036        // consumer — pin the equivalence so the trait remains a drop-in
35037        // replacement. Also cross-checks that all three input shapes
35038        // (`&'static str` → `.into()`, `String` → `.clone()` /
35039        // `.to_string()`, integer → `.to_string()`) converge on the same
35040        // `Value::String` promotion, since the ~17 call sites cover all
35041        // three input flavors.
35042        let mut via_trait = serde_yaml::Mapping::new();
35043        via_trait.insert_string(KUBE_KEY_KIND, "Gateway");
35044        via_trait.insert_string(KUBE_KEY_NAME, String::from("hello"));
35045        via_trait.insert_string(KUBE_KEY_PORT, 8080u16.to_string());
35046
35047        let mut via_inline = serde_yaml::Mapping::new();
35048        via_inline.insert_str_key(KUBE_KEY_KIND, serde_yaml::Value::String("Gateway".into()));
35049        via_inline.insert_str_key(
35050            KUBE_KEY_NAME,
35051            serde_yaml::Value::String(String::from("hello")),
35052        );
35053        via_inline.insert_str_key(
35054            KUBE_KEY_PORT,
35055            serde_yaml::Value::String(8080u16.to_string()),
35056        );
35057
35058        assert_eq!(
35059            via_trait, via_inline,
35060            "insert_string(KEY, V) must byte-equal \
35061             insert_str_key(KEY, Value::String(V.into())) — otherwise \
35062             the ~17 routed consumer sites drift silently at emit time"
35063        );
35064    }
35065
35066    #[test]
35067    fn mapping_ext_insert_number_promotes_value_to_yaml_number() {
35068        // The trait method promotes an arbitrary `Into<serde_yaml::Number>`
35069        // value to `Value::Number(value.into())` — pin the promotion so a
35070        // future refactor that reaches for a different `Value` variant
35071        // for the integer-scalar payload (e.g. `Value::Tagged` under a
35072        // K8s Server-Side-Apply typed-field-ownership axis rebrand, or
35073        // the deprecated `Value::String(n.to_string())` "stringy port"
35074        // rendering some pre-Gateway-API-v1 CRDs still shipped with) is
35075        // a compile-visible break, not a silent per-consumer regression
35076        // at the K8s-artifact-emit surface. Peer with
35077        // [`mapping_ext_insert_string_promotes_value_to_yaml_string`] on
35078        // the sibling `insert_string` primitive's string-scalar
35079        // promotion pin.
35080        let mut m = serde_yaml::Mapping::new();
35081        let prior = m.insert_number(KUBE_KEY_PORT, GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT);
35082        assert!(
35083            prior.is_none(),
35084            "insert_number returns None on first insertion, mirroring \
35085             serde_yaml::Mapping::insert"
35086        );
35087        let got = m
35088            .get(KUBE_KEY_PORT)
35089            .expect("inserted key is present under Value::Number promotion");
35090        assert_eq!(
35091            got.as_u64(),
35092            Some(u64::from(GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT)),
35093            "insert_number routes value verbatim through Value::Number \
35094             promotion — the u16 payload survives round-trip as a Number \
35095             the as_u64 accessor decodes verbatim"
35096        );
35097        assert!(
35098            matches!(got, serde_yaml::Value::Number(_)),
35099            "the promoted value is Value::Number, not Value::String — a \
35100             stringy-port drift would emit `port: \"80\"` (rejected by \
35101             Gateway API v1 apiserver as a type mismatch)"
35102        );
35103    }
35104
35105    #[test]
35106    fn mapping_ext_insert_number_returns_prior_value_on_replace() {
35107        // The trait method mirrors [`serde_yaml::Mapping::insert`]'s
35108        // return contract: the prior value at that key, or `None` if
35109        // absent. Pin the replace-returns-prior semantic so a future
35110        // refactor that swaps to a `HashMap::entry`-style flow doesn't
35111        // silently drop the prior-value handoff downstream consumers
35112        // may reach for. Peer with
35113        // [`mapping_ext_insert_string_returns_prior_value_on_replace`] on
35114        // the sibling `insert_string` primitive's replace-semantics pin.
35115        let mut m = serde_yaml::Mapping::new();
35116        m.insert_number(KUBE_KEY_PORT, 80u16);
35117        let prior = m.insert_number(KUBE_KEY_PORT, 443u16);
35118        assert_eq!(
35119            prior.as_ref().and_then(serde_yaml::Value::as_u64),
35120            Some(80),
35121            "insert_number returns the prior value when replacing an \
35122             existing key — the u16 payload round-trips verbatim through \
35123             the returned Value::Number handoff"
35124        );
35125        let got = m
35126            .get(KUBE_KEY_PORT)
35127            .expect("key is still present after replace");
35128        assert_eq!(
35129            got.as_u64(),
35130            Some(443),
35131            "replaced value is now the most-recently-inserted one"
35132        );
35133    }
35134
35135    #[test]
35136    fn mapping_ext_insert_number_matches_hand_written_promotion() {
35137        // Cross-check the trait method against the hand-written
35138        // `mapping.insert_str_key(KEY, Value::Number(N.into()))` shape
35139        // the two lifted caixa-mesh call sites previously carried. A
35140        // drift between the trait method's promotion and the inline
35141        // promotion would silently emit a different YAML mapping (a
35142        // differently-typed scalar, a different `Value` variant) at
35143        // every routed consumer — pin the equivalence so the trait
35144        // remains a drop-in replacement. Two arms pin the axis end-to-
35145        // end: a `u16` typed-const arm (the lifted
35146        // `GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT` external HTTP
35147        // listener-port, cd60fde) and a `u16` typed-field arm (the
35148        // per-`entrada.port` backend-target Servico port routed through
35149        // the `AplicacaoSpec` `:entrada :port` slot).
35150        let mut via_trait = serde_yaml::Mapping::new();
35151        via_trait.insert_number(KUBE_KEY_PORT, GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT);
35152        via_trait.insert_number(GATEWAY_API_KEY_VALUE, 8443u16);
35153
35154        let mut via_inline = serde_yaml::Mapping::new();
35155        via_inline.insert_str_key(
35156            KUBE_KEY_PORT,
35157            serde_yaml::Value::Number(GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT.into()),
35158        );
35159        via_inline.insert_str_key(
35160            GATEWAY_API_KEY_VALUE,
35161            serde_yaml::Value::Number(8443u16.into()),
35162        );
35163
35164        assert_eq!(
35165            via_trait, via_inline,
35166            "insert_number(KEY, N) must byte-equal \
35167             insert_str_key(KEY, Value::Number(N.into())) — otherwise \
35168             the two routed caixa-mesh consumer sites drift silently at \
35169             emit time"
35170        );
35171    }
35172
35173    #[test]
35174    fn mapping_ext_insert_mapping_promotes_value_to_yaml_mapping() {
35175        // The trait method promotes an arbitrary `serde_yaml::Mapping`
35176        // value to `Value::Mapping(value)` — pin the promotion so a
35177        // future refactor that reaches for a different `Value` variant
35178        // for the nested-Mapping payload (e.g. `Value::Tagged` under a
35179        // K8s Server-Side-Apply typed-field-ownership axis rebrand) is
35180        // a compile-visible break, not a silent per-consumer regression
35181        // at the K8s-artifact-emit surface. Peer with
35182        // [`mapping_ext_insert_string_promotes_value_to_yaml_string`] on
35183        // the sibling `insert_string` primitive's scalar-promotion pin
35184        // and with
35185        // [`mapping_ext_insert_str_key_promotes_key_to_yaml_string`] on
35186        // the base `insert_str_key` primitive's key-promotion pin.
35187        let mut inner = serde_yaml::Mapping::new();
35188        inner.insert_string(KUBE_KEY_NAME, "hello-rio");
35189        let mut m = serde_yaml::Mapping::new();
35190        let prior = m.insert_mapping(KUBE_KEY_METADATA, inner.clone());
35191        assert!(
35192            prior.is_none(),
35193            "insert_mapping returns None on first insertion, mirroring \
35194             serde_yaml::Mapping::insert"
35195        );
35196        let got = m
35197            .get(KUBE_KEY_METADATA)
35198            .expect("inserted key is present under Value::Mapping promotion");
35199        assert_eq!(
35200            got,
35201            &serde_yaml::Value::Mapping(inner),
35202            "insert_mapping routes value verbatim through Value::Mapping \
35203             promotion"
35204        );
35205    }
35206
35207    #[test]
35208    fn mapping_ext_insert_mapping_returns_prior_value_on_replace() {
35209        // The trait method mirrors [`serde_yaml::Mapping::insert`]'s
35210        // return contract: the prior value at that key, or `None` if
35211        // absent. Pin the replace-returns-prior semantic so a future
35212        // refactor that swaps to a `HashMap::entry`-style flow doesn't
35213        // silently drop the prior-value handoff downstream consumers
35214        // may reach for. Peer with
35215        // [`mapping_ext_insert_string_returns_prior_value_on_replace`]
35216        // and
35217        // [`mapping_ext_insert_str_key_returns_prior_value_on_replace`]
35218        // on the sibling primitive-pair members' replace-semantics
35219        // pins.
35220        let mut first_inner = serde_yaml::Mapping::new();
35221        first_inner.insert_string(KUBE_KEY_NAME, "first");
35222        let mut second_inner = serde_yaml::Mapping::new();
35223        second_inner.insert_string(KUBE_KEY_NAME, "second");
35224        let mut m = serde_yaml::Mapping::new();
35225        m.insert_mapping(KUBE_KEY_METADATA, first_inner.clone());
35226        let prior = m.insert_mapping(KUBE_KEY_METADATA, second_inner.clone());
35227        assert_eq!(
35228            prior,
35229            Some(serde_yaml::Value::Mapping(first_inner)),
35230            "insert_mapping returns the prior value when replacing an \
35231             existing key"
35232        );
35233        let got = m
35234            .get(KUBE_KEY_METADATA)
35235            .expect("key is still present after replace");
35236        assert_eq!(
35237            got,
35238            &serde_yaml::Value::Mapping(second_inner),
35239            "replaced value is now the most-recently-inserted one"
35240        );
35241    }
35242
35243    #[test]
35244    fn mapping_ext_insert_mapping_matches_hand_written_promotion() {
35245        // Cross-check the trait method against the hand-written
35246        // `mapping.insert_str_key(KEY, Value::Mapping(inner))` shape the
35247        // 6 lifted call sites previously carried. A drift between the
35248        // trait method's promotion and the inline promotion would
35249        // silently emit a different YAML mapping (a differently-wrapped
35250        // outer variant, a differently-shaped inner Mapping) at every
35251        // routed consumer — pin the equivalence so the trait remains a
35252        // drop-in replacement. Two cases pin the shape end-to-end:
35253        // an empty inner Mapping (no silent is_empty short-circuit) and
35254        // a populated inner Mapping (the `metadata` / `spec` /
35255        // `spec.rules[].path` sub-block shape).
35256        let mut inner_empty = serde_yaml::Mapping::new();
35257        let _ = &mut inner_empty; // keep as mut for parity with populated arm below
35258        let mut inner_populated = serde_yaml::Mapping::new();
35259        inner_populated.insert_string(KUBE_KEY_NAME, "hello-rio");
35260        inner_populated.insert_string(KUBE_KEY_NAMESPACE, DEFAULT_NAMESPACE);
35261
35262        let mut via_trait = serde_yaml::Mapping::new();
35263        via_trait.insert_mapping(KUBE_KEY_SPEC, inner_empty.clone());
35264        via_trait.insert_mapping(KUBE_KEY_METADATA, inner_populated.clone());
35265
35266        let mut via_inline = serde_yaml::Mapping::new();
35267        via_inline.insert_str_key(KUBE_KEY_SPEC, serde_yaml::Value::Mapping(inner_empty));
35268        via_inline.insert_str_key(
35269            KUBE_KEY_METADATA,
35270            serde_yaml::Value::Mapping(inner_populated),
35271        );
35272
35273        assert_eq!(
35274            via_trait, via_inline,
35275            "insert_mapping(KEY, inner) must byte-equal \
35276             insert_str_key(KEY, Value::Mapping(inner)) — otherwise the \
35277             six routed consumer sites drift silently at emit time"
35278        );
35279    }
35280
35281    #[test]
35282    fn mapping_ext_insert_sequence_promotes_value_to_yaml_sequence() {
35283        // The trait method promotes an arbitrary `Vec<Value>` value to
35284        // `Value::Sequence(value)` — pin the promotion so a future
35285        // refactor that reaches for a different `Value` variant for the
35286        // list-shape payload (e.g. `Value::Tagged` under a K8s Server-
35287        // Side-Apply typed-field-ownership axis rebrand, a serde_yaml
35288        // successor's `Value::Array` / `Value::List` variant rename) is
35289        // a compile-visible break, not a silent per-consumer regression
35290        // at the K8s-artifact-emit surface. Peer with
35291        // [`mapping_ext_insert_mapping_promotes_value_to_yaml_mapping`]
35292        // on the sibling `insert_mapping` primitive's nested-Mapping-
35293        // promotion pin, and with
35294        // [`mapping_ext_insert_string_promotes_value_to_yaml_string`]
35295        // on the sibling `insert_string` primitive's scalar-promotion
35296        // pin.
35297        let inner = vec![
35298            serde_yaml::Value::String("hello".into()),
35299            serde_yaml::Value::String("world".into()),
35300        ];
35301        let mut m = serde_yaml::Mapping::new();
35302        let prior = m.insert_sequence(GATEWAY_API_KEY_HOSTNAMES, inner.clone());
35303        assert!(
35304            prior.is_none(),
35305            "insert_sequence returns None on first insertion, mirroring \
35306             serde_yaml::Mapping::insert"
35307        );
35308        let got = m
35309            .get(GATEWAY_API_KEY_HOSTNAMES)
35310            .expect("inserted key is present under Value::Sequence promotion");
35311        assert_eq!(
35312            got,
35313            &serde_yaml::Value::Sequence(inner),
35314            "insert_sequence routes value verbatim through Value::Sequence \
35315             promotion"
35316        );
35317    }
35318
35319    #[test]
35320    fn mapping_ext_insert_sequence_returns_prior_value_on_replace() {
35321        // The trait method mirrors [`serde_yaml::Mapping::insert`]'s
35322        // return contract: the prior value at that key, or `None` if
35323        // absent. Pin the replace-returns-prior semantic so a future
35324        // refactor that swaps to a `HashMap::entry`-style flow doesn't
35325        // silently drop the prior-value handoff downstream consumers
35326        // may reach for. Peer with
35327        // [`mapping_ext_insert_mapping_returns_prior_value_on_replace`],
35328        // [`mapping_ext_insert_string_returns_prior_value_on_replace`],
35329        // and
35330        // [`mapping_ext_insert_str_key_returns_prior_value_on_replace`]
35331        // on the sibling primitive-quadruple members' replace-semantics
35332        // pins.
35333        let first: Vec<serde_yaml::Value> = vec![serde_yaml::Value::String("a".into())];
35334        let second: Vec<serde_yaml::Value> = vec![
35335            serde_yaml::Value::String("b".into()),
35336            serde_yaml::Value::String("c".into()),
35337        ];
35338        let mut m = serde_yaml::Mapping::new();
35339        m.insert_sequence(KUBE_KEY_RULES, first.clone());
35340        let prior = m.insert_sequence(KUBE_KEY_RULES, second.clone());
35341        assert_eq!(
35342            prior,
35343            Some(serde_yaml::Value::Sequence(first)),
35344            "insert_sequence returns the prior value when replacing an \
35345             existing key"
35346        );
35347        let got = m
35348            .get(KUBE_KEY_RULES)
35349            .expect("key is still present after replace");
35350        assert_eq!(
35351            got,
35352            &serde_yaml::Value::Sequence(second),
35353            "replaced value is now the most-recently-inserted one"
35354        );
35355    }
35356
35357    #[test]
35358    fn mapping_ext_insert_sequence_matches_hand_written_promotion() {
35359        // Cross-check the trait method against the hand-written
35360        // `mapping.insert_str_key(KEY, Value::Sequence(v))` shape the 4
35361        // lifted call sites previously carried. A drift between the
35362        // trait method's promotion and the inline promotion would
35363        // silently emit a different YAML mapping (a differently-wrapped
35364        // outer variant, a differently-shaped inner sequence) at every
35365        // routed consumer — pin the equivalence so the trait remains a
35366        // drop-in replacement. Three cases pin the shape end-to-end:
35367        // an empty inner Vec (no silent is_empty short-circuit), a
35368        // singleton-Value inner Vec (the `fromEndpoints[<selector>]` /
35369        // `hostnames[<host>]` singleton shape), and a multi-Value inner
35370        // Vec (the `toPorts[…]` / `rules[…]` multi-entry shape).
35371        let inner_empty: Vec<serde_yaml::Value> = Vec::new();
35372        let inner_singleton: Vec<serde_yaml::Value> =
35373            vec![serde_yaml::Value::String("example.com".into())];
35374        let mut host_entry = serde_yaml::Mapping::new();
35375        host_entry.insert_string(KUBE_KEY_NAME, "svc-a");
35376        let mut port_entry = serde_yaml::Mapping::new();
35377        port_entry.insert_string(KUBE_KEY_NAME, "svc-b");
35378        let inner_multi: Vec<serde_yaml::Value> = vec![
35379            serde_yaml::Value::Mapping(host_entry.clone()),
35380            serde_yaml::Value::Mapping(port_entry.clone()),
35381        ];
35382
35383        let mut via_trait = serde_yaml::Mapping::new();
35384        via_trait.insert_sequence(CILIUM_KEY_TO_PORTS, inner_empty.clone());
35385        via_trait.insert_sequence(GATEWAY_API_KEY_HOSTNAMES, inner_singleton.clone());
35386        via_trait.insert_sequence(KUBE_KEY_RULES, inner_multi.clone());
35387
35388        let mut via_inline = serde_yaml::Mapping::new();
35389        via_inline.insert_str_key(
35390            CILIUM_KEY_TO_PORTS,
35391            serde_yaml::Value::Sequence(inner_empty),
35392        );
35393        via_inline.insert_str_key(
35394            GATEWAY_API_KEY_HOSTNAMES,
35395            serde_yaml::Value::Sequence(inner_singleton),
35396        );
35397        via_inline.insert_str_key(KUBE_KEY_RULES, serde_yaml::Value::Sequence(inner_multi));
35398
35399        assert_eq!(
35400            via_trait, via_inline,
35401            "insert_sequence(KEY, v) must byte-equal \
35402             insert_str_key(KEY, Value::Sequence(v)) — otherwise the \
35403             four routed consumer sites drift silently at emit time"
35404        );
35405    }
35406
35407    // ── insert_singleton_mapping_sequence — composed primitive ───────────
35408    //
35409    // The trait method composes [`Self::insert_str_key`] with
35410    // [`singleton_mapping_sequence`]: every hand-inline
35411    // `mapping.insert_str_key(K, singleton_mapping_sequence(m))` two-symbol
35412    // composition previously carried at 7 sites across caixa-mesh
35413    // collapses onto one method call. Three peer pins pin the trait
35414    // method's shape end-to-end.
35415
35416    #[test]
35417    fn mapping_ext_insert_singleton_mapping_sequence_promotes_value_to_singleton_mapping_seq() {
35418        // First-insertion returns None (mirroring [`Mapping::insert`])
35419        // and the inserted value is a `Value::Sequence` of exactly one
35420        // element, wrapping the caller's Mapping as `Value::Mapping`.
35421        // Peer with the sibling
35422        // `mapping_ext_insert_sequence_promotes_value_to_yaml_sequence`
35423        // / `mapping_ext_insert_mapping_promotes_value_to_yaml_mapping`
35424        // / `mapping_ext_insert_string_promotes_value_to_yaml_string`
35425        // first-insert pins on the sibling MappingExt primitive
35426        // members.
35427        let mut inner = serde_yaml::Mapping::new();
35428        inner.insert_str_key(
35429            GATEWAY_API_KEY_NAME,
35430            serde_yaml::Value::String("gw-listener".into()),
35431        );
35432        let mut m = serde_yaml::Mapping::new();
35433        let prior = m.insert_singleton_mapping_sequence(GATEWAY_API_KEY_LISTENERS, inner.clone());
35434        assert_eq!(
35435            prior, None,
35436            "insert_singleton_mapping_sequence returns None on first insertion, \
35437             mirroring serde_yaml::Mapping::insert"
35438        );
35439        let got = m
35440            .get(GATEWAY_API_KEY_LISTENERS)
35441            .expect("inserted key is present under Value::Sequence promotion");
35442        assert_eq!(
35443            got,
35444            &serde_yaml::Value::Sequence(vec![serde_yaml::Value::Mapping(inner)]),
35445            "insert_singleton_mapping_sequence routes value verbatim through \
35446             the singleton_mapping_sequence(_) helper wrap"
35447        );
35448    }
35449
35450    #[test]
35451    fn mapping_ext_insert_singleton_mapping_sequence_returns_prior_value_on_replace() {
35452        // The trait method mirrors [`serde_yaml::Mapping::insert`]'s
35453        // return contract: the prior value at that key, or `None` if
35454        // absent. Pin the replace-returns-prior semantic so a future
35455        // refactor that swaps to a `HashMap::entry`-style flow doesn't
35456        // silently drop the prior-value handoff downstream consumers
35457        // may reach for. Peer with the sibling
35458        // `mapping_ext_insert_sequence_returns_prior_value_on_replace`
35459        // and its siblings on the primitive-quintuple axis.
35460        let mut first = serde_yaml::Mapping::new();
35461        first.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("a".into()));
35462        let mut second = serde_yaml::Mapping::new();
35463        second.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("b".into()));
35464        let mut m = serde_yaml::Mapping::new();
35465        m.insert_singleton_mapping_sequence(GATEWAY_API_KEY_PARENT_REFS, first.clone());
35466        let prior =
35467            m.insert_singleton_mapping_sequence(GATEWAY_API_KEY_PARENT_REFS, second.clone());
35468        assert_eq!(
35469            prior,
35470            Some(serde_yaml::Value::Sequence(vec![
35471                serde_yaml::Value::Mapping(first)
35472            ])),
35473            "insert_singleton_mapping_sequence returns the prior value \
35474             when replacing an existing key"
35475        );
35476        let got = m
35477            .get(GATEWAY_API_KEY_PARENT_REFS)
35478            .expect("key is still present after replace");
35479        assert_eq!(
35480            got,
35481            &serde_yaml::Value::Sequence(vec![serde_yaml::Value::Mapping(second)]),
35482            "replaced value is now the most-recently-inserted singleton \
35483             mapping sequence"
35484        );
35485    }
35486
35487    #[test]
35488    fn mapping_ext_insert_singleton_mapping_sequence_matches_hand_written_composition() {
35489        // Cross-check the trait method against the hand-written
35490        // `mapping.insert_str_key(KEY, singleton_mapping_sequence(m))`
35491        // two-symbol composition the 7 lifted call sites previously
35492        // carried. A drift between the trait method's routing and the
35493        // inline composition would silently emit a different YAML
35494        // mapping (a differently-wrapped outer variant, a
35495        // differently-shaped inner singleton-Mapping list) at every
35496        // routed consumer — pin the equivalence so the trait remains a
35497        // drop-in replacement. Three cases pin the shape end-to-end:
35498        // an empty inner Mapping (no silent is_empty short-circuit,
35499        // matches the sibling `singleton_mapping_sequence_preserves_empty_inner_mapping`
35500        // pin), a single-key inner Mapping (the
35501        // `CILIUM_KEY_HTTP` / `CILIUM_KEY_INGRESS` singleton-rule
35502        // shape), and a multi-key inner Mapping (the
35503        // `GATEWAY_API_KEY_LISTENERS` per-listener shape).
35504        let inner_empty = serde_yaml::Mapping::new();
35505        let mut inner_single_key = serde_yaml::Mapping::new();
35506        inner_single_key
35507            .insert_str_key(CILIUM_KEY_PATH, serde_yaml::Value::String("/health".into()));
35508        let mut inner_multi_key = serde_yaml::Mapping::new();
35509        inner_multi_key.insert_str_key(
35510            GATEWAY_API_KEY_NAME,
35511            serde_yaml::Value::String("http".into()),
35512        );
35513        inner_multi_key.insert_str_key(
35514            KUBE_KEY_PORT,
35515            serde_yaml::Value::Number(GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT.into()),
35516        );
35517
35518        let mut via_trait = serde_yaml::Mapping::new();
35519        via_trait.insert_singleton_mapping_sequence(CILIUM_KEY_HTTP, inner_empty.clone());
35520        via_trait.insert_singleton_mapping_sequence(CILIUM_KEY_INGRESS, inner_single_key.clone());
35521        via_trait
35522            .insert_singleton_mapping_sequence(GATEWAY_API_KEY_LISTENERS, inner_multi_key.clone());
35523
35524        let mut via_inline = serde_yaml::Mapping::new();
35525        via_inline.insert_str_key(CILIUM_KEY_HTTP, singleton_mapping_sequence(inner_empty));
35526        via_inline.insert_str_key(
35527            CILIUM_KEY_INGRESS,
35528            singleton_mapping_sequence(inner_single_key),
35529        );
35530        via_inline.insert_str_key(
35531            GATEWAY_API_KEY_LISTENERS,
35532            singleton_mapping_sequence(inner_multi_key),
35533        );
35534
35535        assert_eq!(
35536            via_trait, via_inline,
35537            "insert_singleton_mapping_sequence(KEY, m) must byte-equal \
35538             insert_str_key(KEY, singleton_mapping_sequence(m)) — otherwise \
35539             the seven routed caixa-mesh consumer sites drift silently at \
35540             emit time"
35541        );
35542    }
35543
35544    // ── entry_str_key — entry-API twin of insert_str_key ─────────────────
35545
35546    #[test]
35547    fn mapping_ext_entry_str_key_or_inserts_default_under_yaml_string_promoted_key_when_absent() {
35548        // The trait method promotes an arbitrary `&str` key to
35549        // `Value::String(key.to_string())` on the entry-API axis — pin
35550        // the promotion + the entry-API contract so a future refactor
35551        // that reaches for a different `Value` variant for the entry
35552        // key (e.g. `Value::Tagged`) or breaks the entry-API
35553        // `.or_insert(...)` composition is a compile-visible break,
35554        // not a silent per-consumer regression at the 4 lifted
35555        // `caixa-flux` idempotent-upsert sites. Peer with the sibling
35556        // [`mapping_ext_insert_str_key_promotes_key_to_yaml_string`] on
35557        // the fresh-emit axis of the same key promotion.
35558        let mut m = serde_yaml::Mapping::new();
35559        let default_val = serde_yaml::Value::Sequence(Vec::new());
35560        let inserted = m.entry_str_key("programs").or_insert(default_val.clone());
35561        assert_eq!(
35562            inserted, &default_val,
35563            "entry_str_key(K).or_insert(D) returns &mut D on the absent-key \
35564             path, mirroring serde_yaml::mapping::Entry::or_insert"
35565        );
35566        // Key is exactly the `Value::String` promotion of the input.
35567        let got = m
35568            .get("programs")
35569            .expect("or_insert-defaulted key is present under Value::String promotion");
35570        assert_eq!(
35571            got, &default_val,
35572            "entry_str_key routes the default verbatim to the underlying \
35573             serde_yaml::Mapping::entry(...).or_insert(...) path"
35574        );
35575    }
35576
35577    #[test]
35578    fn mapping_ext_entry_str_key_leaves_prior_value_untouched_on_or_insert_when_present() {
35579        // The trait method mirrors [`serde_yaml::mapping::Entry::or_insert`]'s
35580        // present-key contract: the prior value is preserved, and the
35581        // returned `&mut Value` points at that prior value (NOT the
35582        // discarded default). Pin the leave-prior-untouched semantic so a
35583        // future refactor that swaps to an `.insert`-style overwrite
35584        // flow doesn't silently clobber every idempotent-upsert consumer
35585        // (the M4 per-`:politicas` overlay merger, the `feira app
35586        // deploy` idempotent-write dry-run comparator). Peer with the
35587        // sibling [`mapping_ext_insert_str_key_returns_prior_value_on_replace`]
35588        // pin on the fresh-emit axis (which mirrors the `insert`
35589        // replace-and-return-prior semantic, not the `entry.or_insert`
35590        // preserve-prior semantic — the two APIs partition the
35591        // `Mapping`-write surface exactly on this axis).
35592        let mut m = serde_yaml::Mapping::new();
35593        m.insert_str_key(
35594            FLEET_PROGRAMS_KEY_PROGRAMS,
35595            serde_yaml::Value::Sequence(vec![serde_yaml::Value::String("existing".into())]),
35596        );
35597        let discarded_default = serde_yaml::Value::Sequence(Vec::new());
35598        let returned = m
35599            .entry_str_key(FLEET_PROGRAMS_KEY_PROGRAMS)
35600            .or_insert(discarded_default);
35601        assert_eq!(
35602            returned,
35603            &serde_yaml::Value::Sequence(vec![serde_yaml::Value::String("existing".into())]),
35604            "entry_str_key(K).or_insert(D) returns &mut prior on the \
35605             present-key path — the discarded default must not overwrite \
35606             the emitter's prior write"
35607        );
35608        // Value at the key is still the pre-existing one, verbatim.
35609        let got = m
35610            .get(FLEET_PROGRAMS_KEY_PROGRAMS)
35611            .expect("key is still present after or_insert on the present-key path");
35612        assert_eq!(
35613            got,
35614            &serde_yaml::Value::Sequence(vec![serde_yaml::Value::String("existing".into())]),
35615            "or_insert on the present-key path preserves the prior value \
35616             verbatim — no clobber, no reshape"
35617        );
35618    }
35619
35620    #[test]
35621    fn mapping_ext_entry_str_key_matches_hand_written_composition() {
35622        // Cross-check the trait method against the hand-written
35623        // `mapping.entry(Value::String(KEY.into()))` three-token
35624        // composition the 4 lifted `caixa-flux` call sites previously
35625        // carried. A drift between the trait method's promotion and the
35626        // inline promotion the prior call sites used would silently
35627        // route every idempotent-upsert consumer past a different bucket
35628        // (a differently-promoted key on absent-key insert, a hash-key
35629        // mismatch that always fires the `or_insert` default even when
35630        // the emitter's `insert_str_key` already wrote a value under
35631        // the same key). Two cases pin the shape end-to-end: an
35632        // absent-key path (both routes take the vacant `or_insert`
35633        // branch, both end up storing the same default under the
35634        // promoted key) and a present-key path (both routes take the
35635        // occupied `or_insert` branch, both leave the prior value
35636        // untouched — the twin of the
35637        // `mapping_ext_insert_str_key_matches_hand_written_promotion`
35638        // pin on the fresh-emit axis).
35639        //
35640        // Absent-key path — the vacant `or_insert` branch.
35641        let mut via_trait_absent = serde_yaml::Mapping::new();
35642        via_trait_absent
35643            .entry_str_key(FLEET_PROGRAMS_KEY_PROGRAMS)
35644            .or_insert(serde_yaml::Value::Sequence(Vec::new()));
35645        let mut via_inline_absent = serde_yaml::Mapping::new();
35646        via_inline_absent
35647            .entry(serde_yaml::Value::String(
35648                FLEET_PROGRAMS_KEY_PROGRAMS.into(),
35649            ))
35650            .or_insert(serde_yaml::Value::Sequence(Vec::new()));
35651        assert_eq!(
35652            via_trait_absent, via_inline_absent,
35653            "entry_str_key(K).or_insert(D) must byte-equal \
35654             entry(Value::String(K.into())).or_insert(D) on the absent-key \
35655             path — otherwise the 4 routed caixa-flux consumer sites \
35656             land the default under a different bucket than the emitter's \
35657             `insert_str_key` write and the idempotent-upsert semantic \
35658             silently doubles the entry on every call"
35659        );
35660
35661        // Present-key path — the occupied `or_insert` branch. Seed both
35662        // mappings via the fresh-emit `insert_str_key` peer (which the
35663        // `matches_hand_written_promotion` pin already gates), so the
35664        // present-key path here inherits the promotion-agreement guarantee
35665        // from that peer and tests only the entry-API branch difference.
35666        let seed = serde_yaml::Value::Mapping(serde_yaml::Mapping::new());
35667        let mut via_trait_present = serde_yaml::Mapping::new();
35668        via_trait_present.insert_str_key(FLUX_KEY_VALUES, seed.clone());
35669        via_trait_present
35670            .entry_str_key(FLUX_KEY_VALUES)
35671            .or_insert(serde_yaml::Value::Sequence(Vec::new()));
35672        let mut via_inline_present = serde_yaml::Mapping::new();
35673        via_inline_present.insert_str_key(FLUX_KEY_VALUES, seed);
35674        via_inline_present
35675            .entry(serde_yaml::Value::String(FLUX_KEY_VALUES.into()))
35676            .or_insert(serde_yaml::Value::Sequence(Vec::new()));
35677        assert_eq!(
35678            via_trait_present, via_inline_present,
35679            "entry_str_key(K).or_insert(D) must byte-equal \
35680             entry(Value::String(K.into())).or_insert(D) on the \
35681             present-key path — otherwise a promoted-key mismatch would \
35682             cause the trait routing to see the seed as absent and \
35683             overwrite the emitter's prior write while the hand-written \
35684             inline routing sees it as present and preserves it (or vice \
35685             versa)"
35686        );
35687    }
35688
35689    // ── entry_or_default_{mapping,sequence} — entry-API-with-container-check ─
35690
35691    #[test]
35692    fn mapping_ext_entry_or_default_mapping_seeds_empty_inner_when_absent() {
35693        // Absent-key path — the helper mints an empty
35694        // `Value::Mapping(Mapping::new())` under the promoted key and
35695        // returns `Some(&mut inner)` pointing at the fresh empty inner.
35696        // Pin the seed shape so a future refactor that reaches for a
35697        // different empty-container variant (e.g. `Value::Null`, or a
35698        // `Mapping::with_capacity(_)` non-empty pre-allocation) or
35699        // breaks the `Option::Some` return contract is a compile-visible
35700        // break, not a silent per-consumer regression at the caixa-flux
35701        // `upsert_into_helmrelease_programs` `spec.values` container-
35702        // upsert. Peer with the sibling
35703        // [`mapping_ext_entry_or_default_sequence_seeds_empty_inner_when_absent`]
35704        // on the sibling list-container axis.
35705        let mut m = serde_yaml::Mapping::new();
35706        {
35707            let inner = m
35708                .entry_or_default_mapping(FLUX_KEY_VALUES)
35709                .expect("absent-key path seeds an empty Mapping and returns Some(&mut _)");
35710            assert!(
35711                inner.is_empty(),
35712                "the seeded default must be an EMPTY Mapping — a \
35713                 non-empty pre-allocation would land a K8s CRD schema \
35714                 pre-populated block the emitter never authored"
35715            );
35716        }
35717        // Key is exactly the `Value::String` promotion of the input,
35718        // and the value is the empty-Mapping seed.
35719        let got = m
35720            .get(FLUX_KEY_VALUES)
35721            .expect("or_default seeded the key under Value::String promotion");
35722        assert_eq!(
35723            got,
35724            &serde_yaml::Value::Mapping(serde_yaml::Mapping::new()),
35725            "entry_or_default_mapping seeds Value::Mapping(Mapping::new()) \
35726             verbatim on the absent-key arm — no reshape, no wrap"
35727        );
35728    }
35729
35730    #[test]
35731    fn mapping_ext_entry_or_default_mapping_preserves_prior_mapping_on_present_arm() {
35732        // Present-key path with matching variant — the helper mirrors
35733        // [`serde_yaml::mapping::Entry::or_insert_with`]'s occupied
35734        // branch: the prior value is preserved, and the returned
35735        // `&mut Mapping` points at that prior inner Mapping (NOT a
35736        // fresh empty default). Pin the leave-prior-untouched semantic
35737        // so a future refactor that reaches for an `.insert`-style
35738        // overwrite flow doesn't silently clobber every idempotent-
35739        // container-upsert consumer (the `feira app deploy` per-cluster
35740        // write path, the M4 per-cluster HelmRelease overlay merger).
35741        let mut m = serde_yaml::Mapping::new();
35742        let mut prior_inner = serde_yaml::Mapping::new();
35743        prior_inner.insert_str_key(HELM_VALUES_KEY_ENABLED, serde_yaml::Value::Bool(true));
35744        m.insert_mapping(FLUX_KEY_VALUES, prior_inner.clone());
35745        {
35746            let inner = m
35747                .entry_or_default_mapping(FLUX_KEY_VALUES)
35748                .expect("present-Mapping-variant path returns Some(&mut prior)");
35749            assert_eq!(
35750                inner, &prior_inner,
35751                "entry_or_default_mapping returns &mut prior on the \
35752                 present-key path — the default empty Mapping must not \
35753                 overwrite the emitter's prior write"
35754            );
35755        }
35756        // Value at the key is still the pre-existing one, verbatim.
35757        let got = m
35758            .get(FLUX_KEY_VALUES)
35759            .expect("key is still present after or_default on the present-key path");
35760        assert_eq!(
35761            got,
35762            &serde_yaml::Value::Mapping(prior_inner),
35763            "or_default on the present-key path preserves the prior \
35764             value verbatim — no clobber, no reshape"
35765        );
35766    }
35767
35768    #[test]
35769    fn mapping_ext_entry_or_default_mapping_returns_none_on_variant_mismatch() {
35770        // Present-key path with mismatched variant — the helper returns
35771        // `None`, letting the caller surface its domain-specific
35772        // "expected Mapping at this schema key" diagnostic (rather than
35773        // silently clobbering the mismatched prior value). Pin the
35774        // structural-mismatch-is-None contract so a future refactor
35775        // that reaches for a fallback-to-empty-default flow doesn't
35776        // silently overwrite user-authored non-Mapping data at the
35777        // canonical caixa-flux `Error::MissingField("spec.values must
35778        // be a mapping")` site — the mismatched-variant arm is
35779        // load-bearing for the domain-error diagnostic path, not just
35780        // a corner case.
35781        let mut m = serde_yaml::Mapping::new();
35782        m.insert_string(FLUX_KEY_VALUES, "not-a-mapping");
35783        let result = m.entry_or_default_mapping(FLUX_KEY_VALUES);
35784        assert!(
35785            result.is_none(),
35786            "entry_or_default_mapping returns None on variant \
35787             mismatch — the caller's `.ok_or(Error::MissingField(_))?` \
35788             chain surfaces the structural type-mismatch diagnostic"
35789        );
35790        let got = m
35791            .get(FLUX_KEY_VALUES)
35792            .expect("mismatched-variant prior value stays present after variant-check");
35793        assert_eq!(
35794            got,
35795            &serde_yaml::Value::String("not-a-mapping".into()),
35796            "None arm on variant mismatch leaves the prior value \
35797             untouched — the caller's domain-error path fires without \
35798             clobbering the user-authored data"
35799        );
35800    }
35801
35802    #[test]
35803    fn mapping_ext_entry_or_default_sequence_seeds_empty_inner_when_absent() {
35804        // Absent-key path — the helper mints an empty
35805        // `Value::Sequence(Vec::new())` under the promoted key and
35806        // returns `Some(&mut inner)` pointing at the fresh empty
35807        // `Vec<Value>`. Peer with
35808        // [`mapping_ext_entry_or_default_mapping_seeds_empty_inner_when_absent`]
35809        // on the nested-Mapping-container axis.
35810        let mut m = serde_yaml::Mapping::new();
35811        {
35812            let inner = m
35813                .entry_or_default_sequence(FLEET_PROGRAMS_KEY_PROGRAMS)
35814                .expect("absent-key path seeds an empty Vec and returns Some(&mut _)");
35815            assert!(
35816                inner.is_empty(),
35817                "the seeded default must be an EMPTY Vec — a non-empty \
35818                 pre-allocation would land a pre-populated fleet-programs \
35819                 list the emitter never authored"
35820            );
35821        }
35822        let got = m
35823            .get(FLEET_PROGRAMS_KEY_PROGRAMS)
35824            .expect("or_default seeded the key under Value::String promotion");
35825        assert_eq!(
35826            got,
35827            &serde_yaml::Value::Sequence(Vec::new()),
35828            "entry_or_default_sequence seeds Value::Sequence(Vec::new()) \
35829             verbatim on the absent-key arm — no reshape, no wrap"
35830        );
35831    }
35832
35833    #[test]
35834    fn mapping_ext_entry_or_default_sequence_preserves_prior_sequence_on_present_arm() {
35835        // Present-key path with matching variant — the helper mirrors
35836        // [`serde_yaml::mapping::Entry::or_insert_with`]'s occupied
35837        // branch: the prior `Vec` is preserved, and the returned
35838        // `&mut Vec<Value>` points at that prior inner Vec (NOT a
35839        // fresh empty default). The exact idempotent-upsert semantic
35840        // caixa-flux's `upsert_into_programs_yaml` /
35841        // `upsert_into_helmrelease_programs` depend on to preserve
35842        // prior `programs[]` entries across per-Servico rewrites.
35843        let mut m = serde_yaml::Mapping::new();
35844        let prior_inner = vec![serde_yaml::Value::String("existing".into())];
35845        m.insert_sequence(FLEET_PROGRAMS_KEY_PROGRAMS, prior_inner.clone());
35846        {
35847            let inner = m
35848                .entry_or_default_sequence(FLEET_PROGRAMS_KEY_PROGRAMS)
35849                .expect("present-Sequence-variant path returns Some(&mut prior)");
35850            assert_eq!(
35851                inner, &prior_inner,
35852                "entry_or_default_sequence returns &mut prior on the \
35853                 present-key path — the default empty Vec must not \
35854                 overwrite the emitter's prior write"
35855            );
35856        }
35857        let got = m
35858            .get(FLEET_PROGRAMS_KEY_PROGRAMS)
35859            .expect("key is still present after or_default on the present-key path");
35860        assert_eq!(
35861            got,
35862            &serde_yaml::Value::Sequence(prior_inner),
35863            "or_default on the present-key path preserves the prior \
35864             value verbatim — no clobber, no reshape"
35865        );
35866    }
35867
35868    #[test]
35869    fn mapping_ext_entry_or_default_sequence_returns_none_on_variant_mismatch() {
35870        // Present-key path with mismatched variant — the helper returns
35871        // `None`, letting the caller surface its domain-specific
35872        // "programs must be a sequence" diagnostic (rather than
35873        // silently clobbering the mismatched prior value). Pin the
35874        // structural-mismatch-is-None contract so a future refactor
35875        // that reaches for a fallback-to-empty-default flow doesn't
35876        // silently overwrite user-authored non-Sequence data at the
35877        // canonical caixa-flux `Error::MissingField("programs must be
35878        // a sequence")` site.
35879        let mut m = serde_yaml::Mapping::new();
35880        m.insert_string(FLEET_PROGRAMS_KEY_PROGRAMS, "not-a-sequence");
35881        let result = m.entry_or_default_sequence(FLEET_PROGRAMS_KEY_PROGRAMS);
35882        assert!(
35883            result.is_none(),
35884            "entry_or_default_sequence returns None on variant \
35885             mismatch — the caller's `.ok_or(Error::MissingField(_))?` \
35886             chain surfaces the structural type-mismatch diagnostic"
35887        );
35888        let got = m
35889            .get(FLEET_PROGRAMS_KEY_PROGRAMS)
35890            .expect("mismatched-variant prior value stays present after variant-check");
35891        assert_eq!(
35892            got,
35893            &serde_yaml::Value::String("not-a-sequence".into()),
35894            "None arm on variant mismatch leaves the prior value \
35895             untouched — the caller's domain-error path fires without \
35896             clobbering the user-authored data"
35897        );
35898    }
35899
35900    // ── insert_str_key_if_some — arity-0-or-1 twin of insert_str_key ─────
35901
35902    #[test]
35903    fn mapping_ext_insert_str_key_if_some_none_arm_leaves_mapping_untouched() {
35904        // The None arm skips the insert entirely — no clone, no
35905        // key-promotion, no bucket touch. Pin the no-op semantic so a
35906        // future refactor that reaches for an `Option::unwrap_or_default`
35907        // shape (which would emit `Value::Null` under the key on the
35908        // None arm) or an `.into_iter().for_each` scaffold (which would
35909        // still walk the bucket-lookup path) is a compile-visible break,
35910        // not a silent per-consumer regression at the 3 lifted
35911        // `caixa-mesh` overlay-insert sites (where the `None` arm is
35912        // the author's default when no `:politicas` slot is set — a
35913        // silent `Value::Null` emission would land a K8s CRD schema
35914        // rejection at every unset-slot Aplicacao).
35915        let mut m = serde_yaml::Mapping::new();
35916        let prior = m.insert_str_key_if_some(CILIUM_KEY_AUTHENTICATION, None);
35917        assert_eq!(
35918            prior, None,
35919            "insert_str_key_if_some(K, None) returns None — no insert \
35920             fires, so no prior value can be surfaced"
35921        );
35922        assert!(
35923            m.get(CILIUM_KEY_AUTHENTICATION).is_none(),
35924            "None arm must leave the key absent — a silent `Value::Null` \
35925             insertion would land a K8s CRD schema rejection at every \
35926             `:politicas`-unset Aplicacao"
35927        );
35928        assert_eq!(
35929            m.len(),
35930            0,
35931            "None arm must not touch any bucket — the Mapping stays \
35932             empty verbatim"
35933        );
35934    }
35935
35936    #[test]
35937    fn mapping_ext_insert_str_key_if_some_some_arm_promotes_key_to_yaml_string() {
35938        // The Some arm clones the borrowed inner value and delegates to
35939        // [`Self::insert_str_key`] — pin the promotion + the first-
35940        // insert-returns-None contract so a future refactor that reaches
35941        // for a different `Value` variant for the key (e.g.
35942        // `Value::Tagged`) or breaks the underlying
35943        // [`serde_yaml::Mapping::insert`] return contract is a compile-
35944        // visible break, not a silent per-consumer regression at the 3
35945        // lifted `caixa-mesh` overlay-insert sites. Peer with the sibling
35946        // [`mapping_ext_insert_str_key_promotes_key_to_yaml_string`] on
35947        // the always-1 arity axis of the same key promotion.
35948        let mut m = serde_yaml::Mapping::new();
35949        let overlay = serde_yaml::Value::Mapping({
35950            let mut inner = serde_yaml::Mapping::new();
35951            inner.insert_str_key(
35952                CILIUM_KEY_MODE,
35953                serde_yaml::Value::String("required".into()),
35954            );
35955            inner
35956        });
35957        let prior = m.insert_str_key_if_some(CILIUM_KEY_AUTHENTICATION, Some(&overlay));
35958        assert_eq!(
35959            prior, None,
35960            "insert_str_key_if_some(K, Some(&V)) returns None on first \
35961             insertion, mirroring serde_yaml::Mapping::insert"
35962        );
35963        // Key is exactly the `Value::String` promotion of the input.
35964        let got = m
35965            .get(CILIUM_KEY_AUTHENTICATION)
35966            .expect("Some arm inserts under the Value::String-promoted key");
35967        assert_eq!(
35968            got, &overlay,
35969            "insert_str_key_if_some routes the borrowed inner value \
35970             through a `.clone()` verbatim to the underlying \
35971             `insert_str_key` path — no reshape, no wrap, no unwrap"
35972        );
35973        // The borrowed input is untouched — the caller can reuse the
35974        // outer overlay binding across the next iteration of a per-
35975        // `(:de, :para)` loop (the exact reuse the three lifted
35976        // caixa-mesh sites depend on).
35977        assert!(
35978            overlay.get(CILIUM_KEY_MODE).is_some(),
35979            "insert_str_key_if_some must not move out of the borrowed \
35980             overlay — the caller-side outer binding stays available \
35981             for the next iteration of the enclosing per-`(:de, :para)` \
35982             or per-rule loop"
35983        );
35984    }
35985
35986    #[test]
35987    fn mapping_ext_insert_str_key_if_some_some_arm_returns_prior_value_on_replace() {
35988        // The Some arm mirrors [`serde_yaml::Mapping::insert`]'s return
35989        // contract on the replace-existing path: the prior value at that
35990        // key, surfaced verbatim. Pin the replace-returns-prior semantic
35991        // so a future refactor that reaches for an `entry.or_insert`-
35992        // style preserve-prior flow doesn't silently swap the axis's
35993        // semantic under the three routed caixa-mesh overlay sites (the
35994        // `:politicas` overlay is meant to override an author-provided
35995        // sub-block if one was present, not preserve it — the
35996        // replace-and-return-prior semantic is load-bearing).
35997        let mut m = serde_yaml::Mapping::new();
35998        let existing = serde_yaml::Value::String("cluster-default".into());
35999        let overlay = serde_yaml::Value::Mapping({
36000            let mut inner = serde_yaml::Mapping::new();
36001            inner.insert_str_key(
36002                GATEWAY_API_KEY_REQUEST,
36003                serde_yaml::Value::String("30s".into()),
36004            );
36005            inner
36006        });
36007        m.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, existing.clone());
36008        let prior = m.insert_str_key_if_some(GATEWAY_API_KEY_TIMEOUTS, Some(&overlay));
36009        assert_eq!(
36010            prior,
36011            Some(existing),
36012            "insert_str_key_if_some(K, Some(&V)) returns the prior value \
36013             when replacing an existing key — the overlay overrides the \
36014             author-provided sub-block; the prior value surfaces so the \
36015             caller can log/compare/roll back if needed"
36016        );
36017        // Value at the key is now the overlay, verbatim.
36018        let got = m
36019            .get(GATEWAY_API_KEY_TIMEOUTS)
36020            .expect("key is still present after replace");
36021        assert_eq!(
36022            got, &overlay,
36023            "replaced value is now the most-recently-inserted overlay — \
36024             the Some arm carries through to the underlying \
36025             `insert_str_key` replace path"
36026        );
36027    }
36028
36029    #[test]
36030    fn mapping_ext_insert_str_key_if_some_matches_hand_written_composition() {
36031        // Cross-check the trait method against the hand-written
36032        // `if let Some(x) = &overlay { m.insert_str_key(K, x.clone()); }`
36033        // three-line block the 3 lifted `caixa-mesh` overlay call sites
36034        // previously carried. A drift between the trait method's
36035        // conditional-insert routing and the inline `if let Some`
36036        // composition would silently emit a different Mapping (a
36037        // present-key `Value::Null` on the None arm, a different clone-
36038        // vs-move policy on the Some arm) at every routed consumer —
36039        // pin the equivalence so the trait remains a drop-in replacement.
36040        // Four cases pin the shape end-to-end: None arm (skip), Some
36041        // arm on absent key (fresh insert), Some arm on present key
36042        // (replace-and-return-prior), None arm on present key (no
36043        // touch — the axis's load-bearing "author's value wins when
36044        // overlay is unset" contract).
36045        let overlay = serde_yaml::Value::Mapping({
36046            let mut inner = serde_yaml::Mapping::new();
36047            inner.insert_str_key(
36048                CILIUM_KEY_MODE,
36049                serde_yaml::Value::String("required".into()),
36050            );
36051            inner
36052        });
36053
36054        // Case 1: None arm on empty mapping — both routes no-op.
36055        let mut via_trait_none = serde_yaml::Mapping::new();
36056        via_trait_none.insert_str_key_if_some(CILIUM_KEY_AUTHENTICATION, None);
36057        let via_inline_none = serde_yaml::Mapping::new();
36058        let overlay_slot_none: Option<serde_yaml::Value> = None;
36059        let mut via_inline_none_mut = via_inline_none.clone();
36060        if let Some(a) = &overlay_slot_none {
36061            via_inline_none_mut.insert_str_key(CILIUM_KEY_AUTHENTICATION, a.clone());
36062        }
36063        assert_eq!(
36064            via_trait_none, via_inline_none_mut,
36065            "insert_str_key_if_some(K, None) must byte-equal \
36066             `if let Some(_) = None {{ … }}` — the no-op arm must not \
36067             emit a stray `Value::Null` under the key"
36068        );
36069
36070        // Case 2: Some arm on empty mapping — both routes fresh-insert.
36071        let mut via_trait_some = serde_yaml::Mapping::new();
36072        via_trait_some.insert_str_key_if_some(CILIUM_KEY_AUTHENTICATION, Some(&overlay));
36073        let mut via_inline_some = serde_yaml::Mapping::new();
36074        let overlay_slot_some = Some(overlay.clone());
36075        if let Some(a) = &overlay_slot_some {
36076            via_inline_some.insert_str_key(CILIUM_KEY_AUTHENTICATION, a.clone());
36077        }
36078        assert_eq!(
36079            via_trait_some, via_inline_some,
36080            "insert_str_key_if_some(K, Some(&V)) must byte-equal \
36081             `if let Some(x) = &Some(V.clone()) {{ m.insert_str_key(K, \
36082             x.clone()); }}` on the fresh-insert path — same clone-and-\
36083             insert semantics under the same Value::String-promoted \
36084             bucket"
36085        );
36086
36087        // Case 3: Some arm on present key — both routes replace-and-
36088        // return-prior.
36089        let existing = serde_yaml::Value::String("cluster-default".into());
36090        let mut via_trait_replace = serde_yaml::Mapping::new();
36091        via_trait_replace.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, existing.clone());
36092        let trait_prior =
36093            via_trait_replace.insert_str_key_if_some(GATEWAY_API_KEY_TIMEOUTS, Some(&overlay));
36094        let mut via_inline_replace = serde_yaml::Mapping::new();
36095        via_inline_replace.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, existing.clone());
36096        let overlay_slot_replace = Some(overlay.clone());
36097        let inline_prior = if let Some(a) = &overlay_slot_replace {
36098            via_inline_replace.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, a.clone())
36099        } else {
36100            None
36101        };
36102        assert_eq!(
36103            trait_prior, inline_prior,
36104            "insert_str_key_if_some replace-and-return-prior must byte-\
36105             equal the hand-written `if let Some {{ insert_str_key }}` \
36106             composition's return"
36107        );
36108        assert_eq!(
36109            via_trait_replace, via_inline_replace,
36110            "insert_str_key_if_some replace-post-state must byte-equal \
36111             the hand-written composition's post-state — the overlay \
36112             overrode the author's value in both routes"
36113        );
36114
36115        // Case 4: None arm on present key — both routes preserve the
36116        // author's value verbatim. The load-bearing "author's value
36117        // wins when overlay is unset" contract the three lifted sites
36118        // depend on.
36119        let mut via_trait_preserve = serde_yaml::Mapping::new();
36120        via_trait_preserve.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, existing.clone());
36121        via_trait_preserve.insert_str_key_if_some(GATEWAY_API_KEY_TIMEOUTS, None);
36122        let mut via_inline_preserve = serde_yaml::Mapping::new();
36123        via_inline_preserve.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, existing.clone());
36124        let overlay_slot_preserve: Option<serde_yaml::Value> = None;
36125        if let Some(a) = &overlay_slot_preserve {
36126            via_inline_preserve.insert_str_key(GATEWAY_API_KEY_TIMEOUTS, a.clone());
36127        }
36128        assert_eq!(
36129            via_trait_preserve, via_inline_preserve,
36130            "insert_str_key_if_some(K, None) on a present key must byte-\
36131             equal the hand-written `if let Some(_) = None {{ … }}` — \
36132             the None arm must preserve the author's value verbatim, \
36133             not clobber it with `Value::Null` or drop the key"
36134        );
36135        assert_eq!(
36136            via_trait_preserve
36137                .get(GATEWAY_API_KEY_TIMEOUTS)
36138                .expect("None arm preserves the pre-existing key"),
36139            &existing,
36140            "None arm on a present key surfaces the author's prior \
36141             value verbatim — the load-bearing contract the three \
36142             lifted `:politicas` overlay sites rest on"
36143        );
36144    }
36145
36146    // ── SequenceExt::push_mapping — Vec<Value>-side sibling ──────────────
36147
36148    #[test]
36149    fn sequence_ext_push_mapping_appends_promoted_mapping_value() {
36150        // The method appends the caller's `Mapping` as a fresh
36151        // `Value::Mapping(_)` element on the tail of `self`. Pin the
36152        // per-append routing (`.push(Value::Mapping(_))`) so a future
36153        // refactor that reaches for a different outer variant (a
36154        // Server-Side-Apply-typed `Value::Tagged`, a fresh singleton-list
36155        // wrap via `singleton_mapping_sequence`) or a different
36156        // Vec-mutation shape (e.g. `.insert(0, _)` shifting the axis
36157        // from append to prepend) is a compile-visible break, not a
36158        // silent per-consumer regression at the 4 lifted `caixa-mesh`
36159        // append sites — where the emission order is load-bearing (the
36160        // Cilium `spec.ingress[].toPorts[]` per-edge order, the
36161        // Gateway API `spec.rules[]` per-path order, the top-level CNP
36162        // and programs.yaml document order all depend on the append
36163        // semantics).
36164        let mut seq: Vec<serde_yaml::Value> = Vec::new();
36165        let mut m = serde_yaml::Mapping::new();
36166        m.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("first".into()));
36167        seq.push_mapping(m.clone());
36168        assert_eq!(
36169            seq.len(),
36170            1,
36171            "push_mapping must append exactly one element — the axis's \
36172             fresh-element semantic"
36173        );
36174        assert_eq!(
36175            seq[0],
36176            serde_yaml::Value::Mapping(m),
36177            "the appended element must be the caller's Mapping wrapped \
36178             verbatim as Value::Mapping — no reshape, no clone-and-drop"
36179        );
36180    }
36181
36182    #[test]
36183    fn sequence_ext_push_mapping_preserves_prior_elements_in_insertion_order() {
36184        // Successive push_mapping calls preserve the caller's per-
36185        // iteration order — the Vec grows at the tail, prior elements
36186        // stay at their prior indices. Pin the insertion-order semantic
36187        // so a future refactor that reaches for a per-append sort /
36188        // dedup / hoist-to-front reordering is a test-visible break,
36189        // not a silent behavior shift at the 4 lifted `caixa-mesh`
36190        // append sites (where THEORY.md §V.2.7 render determinism
36191        // pins the per-iteration emission order to the source
36192        // `:contratos` / `:paths` / `:membros` declaration order).
36193        let mut seq: Vec<serde_yaml::Value> = Vec::new();
36194        let mut first = serde_yaml::Mapping::new();
36195        first.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("a".into()));
36196        let mut second = serde_yaml::Mapping::new();
36197        second.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("b".into()));
36198        let mut third = serde_yaml::Mapping::new();
36199        third.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("c".into()));
36200        seq.push_mapping(first.clone());
36201        seq.push_mapping(second.clone());
36202        seq.push_mapping(third.clone());
36203        assert_eq!(
36204            seq.len(),
36205            3,
36206            "three push_mapping calls append three elements"
36207        );
36208        assert_eq!(
36209            seq,
36210            vec![
36211                serde_yaml::Value::Mapping(first),
36212                serde_yaml::Value::Mapping(second),
36213                serde_yaml::Value::Mapping(third),
36214            ],
36215            "push_mapping preserves per-iteration insertion order — the \
36216             axis's render-determinism contract at the 4 lifted \
36217             `caixa-mesh` append sites"
36218        );
36219    }
36220
36221    #[test]
36222    fn sequence_ext_push_mapping_matches_hand_written_composition() {
36223        // Cross-check the trait method against the hand-written
36224        // `<vec>.push(serde_yaml::Value::Mapping(<M>))` three-token
36225        // block the 4 lifted `caixa-mesh` append call sites previously
36226        // carried. A drift between the trait method's routing and the
36227        // inline `Value::Mapping(_)` promotion would silently emit a
36228        // different `Vec<Value>` (a different outer variant on the
36229        // appended element, a different length, a different order) at
36230        // every routed consumer — pin the equivalence so the trait
36231        // remains a drop-in replacement across the fresh-empty, prior-
36232        // populated, and empty-payload cases.
36233
36234        // Case 1: fresh-empty Vec + non-empty Mapping payload.
36235        let mut inner = serde_yaml::Mapping::new();
36236        inner.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("policy-a".into()));
36237        let mut via_trait: Vec<serde_yaml::Value> = Vec::new();
36238        via_trait.push_mapping(inner.clone());
36239        let mut via_inline: Vec<serde_yaml::Value> = Vec::new();
36240        via_inline.push(serde_yaml::Value::Mapping(inner.clone()));
36241        assert_eq!(
36242            via_trait, via_inline,
36243            "push_mapping(M) on empty Vec must byte-equal \
36244             `.push(Value::Mapping(M))` — same variant-promotion, same \
36245             append semantics"
36246        );
36247
36248        // Case 2: prior-populated Vec + non-empty Mapping payload — pin
36249        // that the append fires at the tail, not at the head or the
36250        // middle.
36251        let seed = serde_yaml::Value::String("seed".into());
36252        let mut via_trait_populated: Vec<serde_yaml::Value> = vec![seed.clone()];
36253        via_trait_populated.push_mapping(inner.clone());
36254        let mut via_inline_populated: Vec<serde_yaml::Value> = vec![seed];
36255        via_inline_populated.push(serde_yaml::Value::Mapping(inner.clone()));
36256        assert_eq!(
36257            via_trait_populated, via_inline_populated,
36258            "push_mapping(M) on populated Vec must byte-equal \
36259             `.push(Value::Mapping(M))` — the append fires at the tail, \
36260             prior elements stay at their prior indices"
36261        );
36262
36263        // Case 3: empty Mapping payload — the axis's "empty-vs-absent"
36264        // distinction the 4 lifted sites rest on. An empty inner
36265        // `Mapping` still round-trips as a `Value::Mapping(<empty>)`
36266        // element, not as a skipped no-op, because some K8s CRD schemas
36267        // (Cilium CNP `spec.ingress[].toPorts[].rules.http[]` with an
36268        // empty match set) require an empty inner object to distinguish
36269        // "explicitly-empty" from "absent".
36270        let mut via_trait_empty: Vec<serde_yaml::Value> = Vec::new();
36271        via_trait_empty.push_mapping(serde_yaml::Mapping::new());
36272        let mut via_inline_empty: Vec<serde_yaml::Value> = Vec::new();
36273        via_inline_empty.push(serde_yaml::Value::Mapping(serde_yaml::Mapping::new()));
36274        assert_eq!(
36275            via_trait_empty, via_inline_empty,
36276            "push_mapping(empty Mapping) must byte-equal \
36277             `.push(Value::Mapping(empty))` — no is_empty()-guarded \
36278             short-circuit, no skip"
36279        );
36280        assert_eq!(
36281            via_trait_empty.len(),
36282            1,
36283            "push_mapping on an empty Mapping still appends one element \
36284             — the axis carries no is_empty() short-circuit"
36285        );
36286    }
36287
36288    #[test]
36289    fn singleton_mapping_sequence_wraps_input_as_sole_element() {
36290        // The helper wraps its input `Mapping` as the single element of
36291        // a `Value::Sequence`. Pin the outer variant shape and the
36292        // exactly-one-element length so a future refactor that reaches
36293        // for a different container (e.g. `Value::Tagged`, a
36294        // 0-or-1-element `Option`-shaped emission axis) is a
36295        // compile-visible break, not a silent per-caller regression at
36296        // every K8s-CRD-list-shape-required emit site.
36297        let mut inner = serde_yaml::Mapping::new();
36298        inner.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("hello".into()));
36299        let out = singleton_mapping_sequence(inner.clone());
36300        match out {
36301            serde_yaml::Value::Sequence(seq) => {
36302                assert_eq!(
36303                    seq.len(),
36304                    1,
36305                    "singleton_mapping_sequence emits exactly one element — \
36306                     the K8s-CRD-list-shape-required singleton axis"
36307                );
36308                assert_eq!(
36309                    seq[0],
36310                    serde_yaml::Value::Mapping(inner),
36311                    "the sole element must be the caller's Mapping wrapped \
36312                     verbatim as Value::Mapping — no reshape, no clone-and-drop"
36313                );
36314            }
36315            other => panic!(
36316                "singleton_mapping_sequence must return Value::Sequence, got {other:?} — \
36317                 an outer-variant drift breaks every K8s-CRD-list-shape consumer"
36318            ),
36319        }
36320    }
36321
36322    #[test]
36323    fn singleton_mapping_sequence_preserves_empty_inner_mapping() {
36324        // An empty inner `Mapping` still round-trips through the helper
36325        // as a `Value::Sequence(vec![Value::Mapping(<empty>)])` — the
36326        // helper carries no "skip-empty" short-circuit (empty-vs-absent
36327        // is the caller's decision; some K8s CRD schemas require an
36328        // empty inner object to distinguish "explicitly-empty" from
36329        // "absent"). Pin the shape so a future refactor that reaches
36330        // for an is_empty()-guarded short-circuit is a test-visible
36331        // break, not a silent behavior shift.
36332        let out = singleton_mapping_sequence(serde_yaml::Mapping::new());
36333        let seq = match out {
36334            serde_yaml::Value::Sequence(s) => s,
36335            other => panic!("expected Value::Sequence, got {other:?}"),
36336        };
36337        assert_eq!(seq.len(), 1, "empty inner still wraps as a 1-element seq");
36338        assert_eq!(
36339            seq[0],
36340            serde_yaml::Value::Mapping(serde_yaml::Mapping::new()),
36341            "the sole element is an empty Value::Mapping, verbatim"
36342        );
36343    }
36344
36345    #[test]
36346    fn singleton_mapping_sequence_byte_equals_hand_written_inline_shape() {
36347        // Cross-check the helper against the hand-written
36348        // `Value::Sequence(vec![Value::Mapping(m)])` three-token shape
36349        // the seven lifted call sites previously carried. A drift
36350        // between the helper's wrapping and the inline shape would
36351        // silently emit a different YAML sequence (a differently-shaped
36352        // outer variant, a differently-wrapped inner Mapping) at every
36353        // routed consumer — pin the byte-equivalence so the helper
36354        // remains a drop-in replacement.
36355        let mut inner = serde_yaml::Mapping::new();
36356        inner.insert_str_key(
36357            GATEWAY_API_KEY_NAME,
36358            serde_yaml::Value::String("gw-listener".into()),
36359        );
36360        inner.insert_str_key(
36361            KUBE_KEY_PORT,
36362            serde_yaml::Value::Number(GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT.into()),
36363        );
36364
36365        let via_helper = singleton_mapping_sequence(inner.clone());
36366        let via_inline = serde_yaml::Value::Sequence(vec![serde_yaml::Value::Mapping(inner)]);
36367
36368        assert_eq!(
36369            via_helper, via_inline,
36370            "singleton_mapping_sequence(m) must byte-equal \
36371             Value::Sequence(vec![Value::Mapping(m)]) — otherwise the \
36372             seven routed caixa-mesh call sites drift silently at emit time"
36373        );
36374    }
36375
36376    #[test]
36377    fn string_keyed_entries_yields_each_string_key_and_value_ref() {
36378        // The lift's load-bearing contract: given a Value::Mapping with
36379        // string keys, yield each `(&str, &Value)` pair in insertion
36380        // order. Both routed renderers (caixa-flux::programs_yaml_entry
36381        // and caixa-helm::build_values_yaml) depend on the yielded pair
36382        // shape to drive their per-destination insert — a drift in
36383        // yielded item type is a compile-visible break, not a silent
36384        // shape shift.
36385        let mut spec = serde_yaml::Mapping::new();
36386        spec.insert_str_key(
36387            COMPUTEUNIT_SPEC_KEY_MODULE,
36388            serde_yaml::Value::String("oci://…".into()),
36389        );
36390        spec.insert_str_key(
36391            COMPUTEUNIT_SPEC_KEY_TRIGGER,
36392            serde_yaml::Value::String("http".into()),
36393        );
36394        spec.insert_str_key(
36395            COMPUTEUNIT_SPEC_KEY_CAPABILITIES,
36396            serde_yaml::Value::Sequence(vec![]),
36397        );
36398        let v = serde_yaml::Value::Mapping(spec);
36399        let keys: Vec<&str> = string_keyed_entries(&v).map(|(k, _)| k).collect();
36400        assert_eq!(
36401            keys,
36402            vec![
36403                COMPUTEUNIT_SPEC_KEY_MODULE,
36404                COMPUTEUNIT_SPEC_KEY_TRIGGER,
36405                COMPUTEUNIT_SPEC_KEY_CAPABILITIES,
36406            ],
36407            "string_keyed_entries must yield every string-keyed entry in \
36408             the underlying Mapping's insertion order — both routed \
36409             renderers depend on `spec.module` reaching the destination \
36410             ahead of `spec.trigger` ahead of `spec.capabilities` so the \
36411             emitted values.yaml / programs.yaml entry's key order tracks \
36412             the upstream ComputeUnit YAML author's order"
36413        );
36414        // The paired &Value ref also reaches through — sanity-check on
36415        // the second axis of the yielded tuple.
36416        let module = string_keyed_entries(&v)
36417            .find(|(k, _)| *k == COMPUTEUNIT_SPEC_KEY_MODULE)
36418            .map(|(_, v)| v.clone())
36419            .expect("module entry present");
36420        assert_eq!(module, serde_yaml::Value::String("oci://…".into()));
36421    }
36422
36423    #[test]
36424    fn string_keyed_entries_short_circuits_on_non_mapping_shapes() {
36425        // The prior inline `if let Value::Mapping(_) = spec { … }` arm
36426        // silently no-oped on every non-Mapping shape (Null / String /
36427        // Sequence / Number / Bool). The lift's iterator surface pins
36428        // the same contract: a non-Mapping Value contributes zero
36429        // yielded entries. Pinned because both routed renderers'
36430        // "always splice `spec.*` if it's a Mapping, otherwise skip"
36431        // contract is upstream-schema-validated at the ComputeUnit CRD
36432        // parser but not at the renderer entry point — so a legally-
36433        // authored `spec: null` short-circuits without raising.
36434        for shape in [
36435            serde_yaml::Value::Null,
36436            serde_yaml::Value::String("scalar".into()),
36437            serde_yaml::Value::Sequence(vec![]),
36438            serde_yaml::Value::Number(0.into()),
36439            serde_yaml::Value::Bool(false),
36440        ] {
36441            let count = string_keyed_entries(&shape).count();
36442            assert_eq!(
36443                count, 0,
36444                "string_keyed_entries({shape:?}) must yield zero entries — \
36445                 the prior `if let Value::Mapping(_)` arm silently \
36446                 short-circuited on this shape, so the lift must preserve \
36447                 that no-op contract or every routed renderer regresses on \
36448                 the legally-authored non-Mapping `spec:` axis"
36449            );
36450        }
36451    }
36452
36453    #[test]
36454    fn string_keyed_entries_drops_non_string_keys() {
36455        // serde_yaml permits arbitrary `Value` keys — numeric, boolean,
36456        // sub-mapping — that don't round-trip through the downstream
36457        // K8s YAML-key surface (which requires string keys). Both
36458        // routed renderers previously carried an inline `if let Some(s)
36459        // = k.as_str()` filter to silently drop these; pin the lift's
36460        // filter contract so a future refactor that reaches for
36461        // `.as_str().unwrap()` (which would panic on a numeric key) is
36462        // a test-visible break, not a runtime regression at the first
36463        // ComputeUnit YAML that carries one.
36464        let mut spec = serde_yaml::Mapping::new();
36465        spec.insert(
36466            serde_yaml::Value::String(COMPUTEUNIT_SPEC_KEY_MODULE.into()),
36467            serde_yaml::Value::String("oci://…".into()),
36468        );
36469        spec.insert(
36470            serde_yaml::Value::Number(42.into()),
36471            serde_yaml::Value::String("dropped".into()),
36472        );
36473        spec.insert(
36474            serde_yaml::Value::Bool(true),
36475            serde_yaml::Value::String("also-dropped".into()),
36476        );
36477        spec.insert(
36478            serde_yaml::Value::String(COMPUTEUNIT_SPEC_KEY_TRIGGER.into()),
36479            serde_yaml::Value::String("http".into()),
36480        );
36481        let v = serde_yaml::Value::Mapping(spec);
36482        let keys: Vec<&str> = string_keyed_entries(&v).map(|(k, _)| k).collect();
36483        assert_eq!(
36484            keys,
36485            vec![COMPUTEUNIT_SPEC_KEY_MODULE, COMPUTEUNIT_SPEC_KEY_TRIGGER],
36486            "string_keyed_entries must silently drop non-string-keyed \
36487             entries (Value::Number, Value::Bool, Value::Mapping keys) \
36488             — the K8s YAML-key surface downstream requires string keys, \
36489             and every routed renderer's inline `k.as_str()` filter \
36490             expected exactly this drop-not-panic contract"
36491        );
36492    }
36493
36494    #[test]
36495    fn string_keyed_entries_matches_prior_inline_walk() {
36496        // Cross-check the helper's yielded sequence against the prior
36497        // inline `if let Value::Mapping(_) = spec { for (k, v) in _ {
36498        // if let Some(s) = k.as_str() { <collect (s, v.clone())> } } }`
36499        // walk both renderers previously carried. A drift between the
36500        // helper's yielded sequence and the inline walk would silently
36501        // emit a different destination map at every routed consumer —
36502        // pin the byte-equivalence so the helper remains a drop-in
36503        // replacement for both renderers' prior five-line block.
36504        let mut spec = serde_yaml::Mapping::new();
36505        spec.insert_str_key(
36506            COMPUTEUNIT_SPEC_KEY_MODULE,
36507            serde_yaml::Value::String("oci://ghcr.io/pleme-io/hello-rio:0.1.0".into()),
36508        );
36509        spec.insert(
36510            serde_yaml::Value::Number(1.into()),
36511            serde_yaml::Value::String("silently-dropped".into()),
36512        );
36513        spec.insert_str_key(
36514            COMPUTEUNIT_SPEC_KEY_TRIGGER,
36515            serde_yaml::Value::String("http".into()),
36516        );
36517        let v = serde_yaml::Value::Mapping(spec);
36518
36519        let via_helper: Vec<(String, serde_yaml::Value)> = string_keyed_entries(&v)
36520            .map(|(k, v)| (k.to_string(), v.clone()))
36521            .collect();
36522
36523        let mut via_inline: Vec<(String, serde_yaml::Value)> = Vec::new();
36524        if let serde_yaml::Value::Mapping(map) = &v {
36525            for (k, v) in map {
36526                if let Some(s) = k.as_str() {
36527                    via_inline.push((s.to_string(), v.clone()));
36528                }
36529            }
36530        }
36531
36532        assert_eq!(
36533            via_helper, via_inline,
36534            "string_keyed_entries must yield the same (String, Value) \
36535             sequence as the prior inline `if let Value::Mapping + for + \
36536             if let Some(k.as_str())` walk — otherwise the two routed \
36537             renderers drift silently at ComputeUnit-YAML-`spec.*`-splice \
36538             time"
36539        );
36540    }
36541
36542    #[test]
36543    fn kube_metadata_str_field_reads_metadata_name_and_namespace_string_scalars() {
36544        // The lift's load-bearing contract: given a Value carrying a
36545        // top-level `metadata: { name: <str>, namespace: <str> }` block
36546        // (every K8s CR document the emit-side `kube_resource_skeleton`
36547        // renders), the helper returns Some(<str>) borrowing into the
36548        // input Value. Pinned because every routed test-side site (the
36549        // six caixa-mesh CNP filters + the caixa-flux kustomization.yaml
36550        // pin) reaches through this exact string-scalar readback, and a
36551        // drift in the borrowed-string contract would silently regress
36552        // every routed site's per-CR filter equality.
36553        let mut metadata = serde_yaml::Mapping::new();
36554        metadata.insert_str_key(
36555            KUBE_KEY_NAME,
36556            serde_yaml::Value::String("checkout-cart-to-catalog".into()),
36557        );
36558        metadata.insert_str_key(
36559            KUBE_KEY_NAMESPACE,
36560            serde_yaml::Value::String(DEFAULT_NAMESPACE.into()),
36561        );
36562        let mut cr = serde_yaml::Mapping::new();
36563        cr.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(metadata));
36564        let value = serde_yaml::Value::Mapping(cr);
36565
36566        assert_eq!(
36567            kube_metadata_str_field(&value, KUBE_KEY_NAME),
36568            Some("checkout-cart-to-catalog"),
36569            "kube_metadata_str_field must read metadata.name as a string \
36570             scalar — the six caixa-mesh CNP per-`(:de, :para)` filter \
36571             sites reach through this axis for policy-identity equality"
36572        );
36573        assert_eq!(
36574            kube_metadata_str_field(&value, KUBE_KEY_NAMESPACE),
36575            Some(DEFAULT_NAMESPACE),
36576            "kube_metadata_str_field must read metadata.namespace as a \
36577             string scalar — the caixa-flux programs_yaml_entry \
36578             production readback + the cluster_bundle kustomization.yaml \
36579             test pin both reach through this axis"
36580        );
36581    }
36582
36583    #[test]
36584    fn kube_metadata_str_field_returns_none_when_metadata_block_absent() {
36585        // Every K8s CR document the emit-side `kube_resource_skeleton`
36586        // renders carries a `metadata:` block, but the readback surface
36587        // is called on arbitrary Value inputs (upstream ComputeUnit
36588        // YAML documents, external YAML documents parsed by tests) that
36589        // may legally omit the block. The prior inline three-hop chain
36590        // silently short-circuits on the first `.get(KUBE_KEY_METADATA)`
36591        // hop when the block is absent; pin the helper's None return so
36592        // the prior no-panic contract holds. The two production-shape
36593        // paths — caixa-flux's `programs_yaml_entry` production
36594        // readback with `.unwrap_or(DEFAULT_NAMESPACE)` fallback, the
36595        // caixa-mesh test-side `.unwrap()` after equality-filter —
36596        // both depend on this None-arm for their fallback / test-harness
36597        // semantics.
36598        let value = serde_yaml::Value::Mapping(serde_yaml::Mapping::new());
36599        assert_eq!(
36600            kube_metadata_str_field(&value, KUBE_KEY_NAME),
36601            None,
36602            "kube_metadata_str_field must short-circuit to None when the \
36603             top-level `metadata:` block is absent — the prior inline \
36604             chain's `.get(KUBE_KEY_METADATA)` outer hop returned None \
36605             here, and every routed caller (production fallback + test \
36606             expect) depends on the None-arm reaching through"
36607        );
36608
36609        // Also verify the shape on a non-Mapping outer Value — the K8s
36610        // CR readback surface accepts arbitrary Value inputs, including
36611        // the Value::Null / Value::Sequence / Value::String shapes an
36612        // external YAML document may parse into.
36613        for shape in [
36614            serde_yaml::Value::Null,
36615            serde_yaml::Value::String("scalar".into()),
36616            serde_yaml::Value::Sequence(vec![]),
36617            serde_yaml::Value::Number(0.into()),
36618            serde_yaml::Value::Bool(false),
36619        ] {
36620            assert_eq!(
36621                kube_metadata_str_field(&shape, KUBE_KEY_NAME),
36622                None,
36623                "kube_metadata_str_field({shape:?}, KUBE_KEY_NAME) must \
36624                 return None on non-Mapping shapes — the prior inline \
36625                 `.get(KUBE_KEY_METADATA)` hop yields None on every \
36626                 non-Mapping Value, and the lift must preserve that \
36627                 contract"
36628            );
36629        }
36630    }
36631
36632    #[test]
36633    fn kube_metadata_str_field_returns_none_when_requested_field_absent() {
36634        // A `metadata:` block present but missing the requested axis-key
36635        // — a well-formed K8s CR that legally omits the requested field
36636        // (a Cluster-scoped CR omits `metadata.namespace`, a
36637        // Server-Side-Apply-authored CR omits `metadata.name` in favor
36638        // of `metadata.generateName`). Every routed caller expects the
36639        // three-hop chain to short-circuit through here to None; pin
36640        // the middle-hop None-arm so a future refactor that reaches for
36641        // `.get(field).unwrap()` (which would panic on a legally-omitted
36642        // axis-key) is a test-visible break.
36643        let mut metadata = serde_yaml::Mapping::new();
36644        metadata.insert_str_key(
36645            KUBE_KEY_NAME,
36646            serde_yaml::Value::String("cluster-scoped-cr".into()),
36647        );
36648        let mut cr = serde_yaml::Mapping::new();
36649        cr.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(metadata));
36650        let value = serde_yaml::Value::Mapping(cr);
36651        assert_eq!(
36652            kube_metadata_str_field(&value, KUBE_KEY_NAMESPACE),
36653            None,
36654            "kube_metadata_str_field must return None when the requested \
36655             `metadata.<field>` axis-key is absent — the prior inline \
36656             chain's middle `.and_then(|m| m.get(<FIELD>))` hop short- \
36657             circuited here, and the lift must preserve that None-arm \
36658             for every legally-omitted axis-key"
36659        );
36660    }
36661
36662    #[test]
36663    fn kube_metadata_str_field_returns_none_when_field_carries_non_string_type() {
36664        // A `metadata.<field>` axis-key present but carrying a non-
36665        // string YAML type — schema-invalid per the K8s apiserver's
36666        // OpenAPI schema but tolerated here as None so the readback
36667        // stays a total function. The prior inline chain's trailing
36668        // `.and_then(|n| n.as_str())` shape gate silently short-
36669        // circuits here; pin the helper's None-arm so a future refactor
36670        // that reaches for `.as_str().unwrap()` (which would panic on
36671        // a numeric axis-value) is a test-visible break, not a runtime
36672        // regression at the first schema-invalid CR the reader sees.
36673        for non_string in [
36674            serde_yaml::Value::Null,
36675            serde_yaml::Value::Number(42.into()),
36676            serde_yaml::Value::Bool(true),
36677            serde_yaml::Value::Sequence(vec![]),
36678            serde_yaml::Value::Mapping(serde_yaml::Mapping::new()),
36679        ] {
36680            let mut metadata = serde_yaml::Mapping::new();
36681            metadata.insert_str_key(KUBE_KEY_NAME, non_string.clone());
36682            let mut cr = serde_yaml::Mapping::new();
36683            cr.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(metadata));
36684            let value = serde_yaml::Value::Mapping(cr);
36685            assert_eq!(
36686                kube_metadata_str_field(&value, KUBE_KEY_NAME),
36687                None,
36688                "kube_metadata_str_field must return None when \
36689                 metadata.name carries a non-string YAML type ({non_string:?}) \
36690                 — the prior inline chain's `.and_then(|n| n.as_str())` \
36691                 shape gate short-circuited here, and every routed caller \
36692                 depends on that None-arm to keep the readback total"
36693            );
36694        }
36695    }
36696
36697    #[test]
36698    fn kube_metadata_str_field_matches_prior_inline_chain() {
36699        // Cross-check the helper's output byte-for-byte against the
36700        // prior inline three-hop chain both routed callers previously
36701        // carried. A drift between the helper's return and the inline
36702        // chain would silently regress every routed test-side filter's
36703        // equality comparison + the caixa-flux production readback's
36704        // fallback semantics — pin the byte-equivalence so the helper
36705        // remains a drop-in replacement for every routed site's prior
36706        // three-line block.
36707        let mut metadata = serde_yaml::Mapping::new();
36708        metadata.insert_str_key(
36709            KUBE_KEY_NAME,
36710            serde_yaml::Value::String("checkout-payment-to-cart".into()),
36711        );
36712        metadata.insert_str_key(
36713            KUBE_KEY_NAMESPACE,
36714            serde_yaml::Value::String(DEFAULT_NAMESPACE.into()),
36715        );
36716        let mut cr = serde_yaml::Mapping::new();
36717        cr.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(metadata));
36718        let value = serde_yaml::Value::Mapping(cr);
36719
36720        for field in [KUBE_KEY_NAME, KUBE_KEY_NAMESPACE] {
36721            let via_helper = kube_metadata_str_field(&value, field);
36722            let via_inline = value
36723                .get(KUBE_KEY_METADATA)
36724                .and_then(|m| m.get(field))
36725                .and_then(|n| n.as_str());
36726            assert_eq!(
36727                via_helper, via_inline,
36728                "kube_metadata_str_field(_, {field:?}) must yield the same \
36729                 Option<&str> as the prior inline three-hop chain — \
36730                 otherwise every routed caller's equality-filter / \
36731                 production-fallback drifts silently at readback time"
36732            );
36733        }
36734    }
36735
36736    #[test]
36737    fn kube_root_str_field_reads_api_version_and_kind_string_scalars() {
36738        // The lift's load-bearing contract: given a Value carrying
36739        // top-level `apiVersion:` + `kind:` string scalars (every K8s
36740        // CR document the emit-side `kube_resource_skeleton` renders
36741        // spells the pair by construction), the helper returns
36742        // Some(<str>) borrowing into the input Value on both axes.
36743        // Pinned because every routed test-side site — the
36744        // caixa-flux `cluster_bundle_*_uses_lifted_flux_api_version`
36745        // per-document apiVersion pins + the caixa-mesh
36746        // `gateway_routes` per-`(Gateway, HTTPRoute)` kind-filter
36747        // + the sibling caixa-mesh
36748        // `cilium_authentication_mode_serialized_as_yaml_string`
36749        // CNP-kind filter — reaches through this exact top-level
36750        // string-scalar readback, and a drift in the borrowed-string
36751        // contract would silently regress every routed site's
36752        // per-CR filter / discriminator-pin equality.
36753        let mut cr = serde_yaml::Mapping::new();
36754        cr.insert_str_key(
36755            KUBE_KEY_API_VERSION,
36756            serde_yaml::Value::String(GATEWAY_API_API_VERSION.into()),
36757        );
36758        cr.insert_str_key(
36759            KUBE_KEY_KIND,
36760            serde_yaml::Value::String(GATEWAY_API_KIND_GATEWAY.into()),
36761        );
36762        let value = serde_yaml::Value::Mapping(cr);
36763
36764        assert_eq!(
36765            kube_root_str_field(&value, KUBE_KEY_API_VERSION),
36766            Some(GATEWAY_API_API_VERSION),
36767            "kube_root_str_field must read top-level apiVersion as a \
36768             string scalar — the caixa-flux `cluster_bundle_*_uses_\
36769             lifted_flux_api_version` pins + caixa-mesh per-CR \
36770             apiVersion pins reach through this axis for discriminator \
36771             equality"
36772        );
36773        assert_eq!(
36774            kube_root_str_field(&value, KUBE_KEY_KIND),
36775            Some(GATEWAY_API_KIND_GATEWAY),
36776            "kube_root_str_field must read top-level kind as a string \
36777             scalar — the 15 caixa-mesh `gateway_routes` per-CR find \
36778             sites reach through this axis to filter the multi-doc \
36779             emission sequence by kind discriminator"
36780        );
36781    }
36782
36783    #[test]
36784    fn kube_root_str_field_returns_none_when_field_absent() {
36785        // Every K8s CR document the emit-side `kube_resource_skeleton`
36786        // renders carries `apiVersion:` + `kind:` scalars, but the
36787        // readback surface is called on arbitrary Value inputs
36788        // (multi-doc sequences under iteration, upstream ComputeUnit
36789        // YAML documents) that may legally omit either axis-key. The
36790        // prior inline two-hop chain silently short-circuits on the
36791        // outer `.get(field)` hop when the axis is absent; pin the
36792        // helper's None return so the prior no-panic contract holds.
36793        // Also verify on non-Mapping outer Value shapes an external
36794        // YAML document may parse into.
36795        let value = serde_yaml::Value::Mapping(serde_yaml::Mapping::new());
36796        assert_eq!(
36797            kube_root_str_field(&value, KUBE_KEY_API_VERSION),
36798            None,
36799            "kube_root_str_field must short-circuit to None when the \
36800             requested top-level axis-key is absent — the prior inline \
36801             `.get(field)` outer hop returned None here, and every \
36802             routed caller (test pin + filter predicate) depends on \
36803             that None-arm reaching through"
36804        );
36805        assert_eq!(
36806            kube_root_str_field(&value, KUBE_KEY_KIND),
36807            None,
36808            "kube_root_str_field must short-circuit to None on a \
36809             missing top-level kind axis-key — every routed \
36810             caixa-mesh find-predicate compares against Some(<KIND>) \
36811             and must reject None-shaped entries silently"
36812        );
36813
36814        for shape in [
36815            serde_yaml::Value::Null,
36816            serde_yaml::Value::String("scalar".into()),
36817            serde_yaml::Value::Sequence(vec![]),
36818            serde_yaml::Value::Number(0.into()),
36819            serde_yaml::Value::Bool(false),
36820        ] {
36821            assert_eq!(
36822                kube_root_str_field(&shape, KUBE_KEY_KIND),
36823                None,
36824                "kube_root_str_field({shape:?}, KUBE_KEY_KIND) must \
36825                 return None on non-Mapping shapes — the prior inline \
36826                 `.get(field)` hop yields None on every non-Mapping \
36827                 Value, and the lift must preserve that contract"
36828            );
36829        }
36830    }
36831
36832    #[test]
36833    fn kube_root_str_field_returns_none_when_field_carries_non_string_type() {
36834        // A top-level `<field>` axis-key present but carrying a non-
36835        // string YAML type — schema-invalid per the K8s apiserver's
36836        // OpenAPI schema but tolerated here as None so the readback
36837        // stays a total function. The prior inline chain's trailing
36838        // `.and_then(|n| n.as_str())` shape gate silently short-
36839        // circuits here; pin the helper's None-arm so a future
36840        // refactor that reaches for `.as_str().unwrap()` (which would
36841        // panic on a numeric axis-value) is a test-visible break, not
36842        // a runtime regression at the first schema-invalid CR the
36843        // reader sees.
36844        for non_string in [
36845            serde_yaml::Value::Null,
36846            serde_yaml::Value::Number(42.into()),
36847            serde_yaml::Value::Bool(true),
36848            serde_yaml::Value::Sequence(vec![]),
36849            serde_yaml::Value::Mapping(serde_yaml::Mapping::new()),
36850        ] {
36851            let mut cr = serde_yaml::Mapping::new();
36852            cr.insert_str_key(KUBE_KEY_KIND, non_string.clone());
36853            let value = serde_yaml::Value::Mapping(cr);
36854            assert_eq!(
36855                kube_root_str_field(&value, KUBE_KEY_KIND),
36856                None,
36857                "kube_root_str_field must return None when top-level \
36858                 kind carries a non-string YAML type ({non_string:?}) \
36859                 — the prior inline `.and_then(|n| n.as_str())` shape \
36860                 gate short-circuited here, and every routed caller \
36861                 depends on that None-arm to keep the readback total"
36862            );
36863        }
36864    }
36865
36866    #[test]
36867    fn kube_root_str_field_matches_prior_inline_chain() {
36868        // Cross-check the helper's output byte-for-byte against the
36869        // prior inline two-hop chain both routed renderers previously
36870        // carried. A drift between the helper's return and the inline
36871        // chain would silently regress every routed test-side filter's
36872        // equality comparison + the caixa-flux production-shape
36873        // per-document apiVersion / kind pin — pin the byte-
36874        // equivalence so the helper remains a drop-in replacement for
36875        // every routed site's prior two-line block.
36876        let mut cr = serde_yaml::Mapping::new();
36877        cr.insert_str_key(
36878            KUBE_KEY_API_VERSION,
36879            serde_yaml::Value::String(FLUX_HELMRELEASE_API_VERSION.into()),
36880        );
36881        cr.insert_str_key(
36882            KUBE_KEY_KIND,
36883            serde_yaml::Value::String(FLUX_KIND_HELM_RELEASE.into()),
36884        );
36885        let value = serde_yaml::Value::Mapping(cr);
36886
36887        for field in [KUBE_KEY_API_VERSION, KUBE_KEY_KIND] {
36888            let via_helper = kube_root_str_field(&value, field);
36889            let via_inline = value.get(field).and_then(|n| n.as_str());
36890            assert_eq!(
36891                via_helper, via_inline,
36892                "kube_root_str_field(_, {field:?}) must yield the same \
36893                 Option<&str> as the prior inline two-hop chain — \
36894                 otherwise every routed caller's equality-filter / \
36895                 discriminator-pin drifts silently at readback time"
36896            );
36897        }
36898    }
36899
36900    #[test]
36901    fn kube_root_str_field_and_kube_metadata_str_field_bracket_the_readback_surface() {
36902        // Peer-pin: the two lifted K8s-CR readback primitives cover
36903        // orthogonal axes on the same document. Given a full K8s CR
36904        // (top-level `apiVersion:` + `kind:` discriminator pair,
36905        // sub-`metadata.name:` + `metadata.namespace:` identity pair),
36906        // each helper reaches through its own axis and the two
36907        // together enumerate every documented top-level string
36908        // scalar the substrate emits + reads back. Pin the pairing so
36909        // a future refactor that collapses the two into a single
36910        // navigation primitive (or splits one further) surfaces here
36911        // as a test-visible break, not a silent regression at the
36912        // first routed caller's per-CR readback drift.
36913        let mut metadata = serde_yaml::Mapping::new();
36914        metadata.insert_str_key(
36915            KUBE_KEY_NAME,
36916            serde_yaml::Value::String("checkout-cart-to-catalog".into()),
36917        );
36918        metadata.insert_str_key(
36919            KUBE_KEY_NAMESPACE,
36920            serde_yaml::Value::String(DEFAULT_NAMESPACE.into()),
36921        );
36922        let mut cr = serde_yaml::Mapping::new();
36923        cr.insert_str_key(
36924            KUBE_KEY_API_VERSION,
36925            serde_yaml::Value::String(CILIUM_API_VERSION.into()),
36926        );
36927        cr.insert_str_key(
36928            KUBE_KEY_KIND,
36929            serde_yaml::Value::String(CILIUM_KIND_NETWORK_POLICY.into()),
36930        );
36931        cr.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(metadata));
36932        let value = serde_yaml::Value::Mapping(cr);
36933
36934        assert_eq!(
36935            kube_root_str_field(&value, KUBE_KEY_API_VERSION),
36936            Some(CILIUM_API_VERSION)
36937        );
36938        assert_eq!(
36939            kube_root_str_field(&value, KUBE_KEY_KIND),
36940            Some(CILIUM_KIND_NETWORK_POLICY)
36941        );
36942        assert_eq!(
36943            kube_metadata_str_field(&value, KUBE_KEY_NAME),
36944            Some("checkout-cart-to-catalog")
36945        );
36946        assert_eq!(
36947            kube_metadata_str_field(&value, KUBE_KEY_NAMESPACE),
36948            Some(DEFAULT_NAMESPACE)
36949        );
36950    }
36951
36952    #[test]
36953    fn kube_kind_is_matches_lifted_kube_root_str_field_equality_shape() {
36954        // Byte-equivalence pin: the lifted predicate reproduces the
36955        // three-token composition (`kube_root_str_field(v,
36956        // KUBE_KEY_KIND) == Some(<KIND>)`) the 15 caixa-mesh test-side
36957        // `.find`/`.filter` sites previously carried inline. Closes the
36958        // "did the lift accidentally rename the pinned scalar-key axis
36959        // to KUBE_KEY_API_VERSION or drop the `Some(...)` wrap" drift
36960        // class every future re-lift on the peer-axis surface (a
36961        // hypothetical `kube_api_version_is` peer, `kube_group_is` on a
36962        // multi-group router harness) would otherwise reopen.
36963        let mut cr = serde_yaml::Mapping::new();
36964        cr.insert_str_key(
36965            KUBE_KEY_KIND,
36966            serde_yaml::Value::String(GATEWAY_API_KIND_GATEWAY.into()),
36967        );
36968        let value = serde_yaml::Value::Mapping(cr);
36969
36970        assert!(kube_kind_is(&value, GATEWAY_API_KIND_GATEWAY));
36971        assert_eq!(
36972            kube_kind_is(&value, GATEWAY_API_KIND_GATEWAY),
36973            kube_root_str_field(&value, KUBE_KEY_KIND) == Some(GATEWAY_API_KIND_GATEWAY),
36974        );
36975    }
36976
36977    #[test]
36978    fn kube_kind_is_false_on_mismatched_kind_and_missing_kind() {
36979        // Complement-side pin: the predicate returns `false` when
36980        // either the kind axis carries a different discriminator or the
36981        // top-level `kind:` scalar is absent altogether (the same
36982        // vacuous-`None` short-circuit the parent
36983        // `kube_root_str_field` closes on the underlying two-hop
36984        // navigation). Consumer sites (`docs.iter().find(|d|
36985        // kube_kind_is(d, X))`) rely on the false-on-mismatch shape to
36986        // skip the wrong CRs across the multi-doc mesh emission and
36987        // land on the intended per-kind document.
36988        let mut cr_wrong_kind = serde_yaml::Mapping::new();
36989        cr_wrong_kind.insert_str_key(
36990            KUBE_KEY_KIND,
36991            serde_yaml::Value::String(GATEWAY_API_KIND_HTTP_ROUTE.into()),
36992        );
36993        assert!(!kube_kind_is(
36994            &serde_yaml::Value::Mapping(cr_wrong_kind),
36995            GATEWAY_API_KIND_GATEWAY,
36996        ));
36997
36998        let cr_no_kind = serde_yaml::Mapping::new();
36999        assert!(!kube_kind_is(
37000            &serde_yaml::Value::Mapping(cr_no_kind),
37001            GATEWAY_API_KIND_GATEWAY,
37002        ));
37003    }
37004
37005    #[test]
37006    fn find_by_kind_matches_inline_iter_find_kube_kind_is_shape() {
37007        // Byte-equivalence pin: the lifted navigator reproduces the
37008        // three-token combinator chain (`docs.iter().find(|d|
37009        // kube_kind_is(d, <KIND>))`) the 14 caixa-mesh test-side
37010        // per-Gateway / per-HTTPRoute find-by-kind sites previously
37011        // carried inline. Closes the "did the lift accidentally
37012        // widen the receiver, drop the closure, or swap `find` for
37013        // `filter`" drift class every future re-lift on the sibling
37014        // multi-doc-navigator axis (a hypothetical
37015        // `filter_by_kind` peer that carries the same underlying
37016        // predicate but returns an iterator) would otherwise reopen.
37017        let mut gateway = serde_yaml::Mapping::new();
37018        gateway.insert_str_key(
37019            KUBE_KEY_KIND,
37020            serde_yaml::Value::String(GATEWAY_API_KIND_GATEWAY.into()),
37021        );
37022        let mut route = serde_yaml::Mapping::new();
37023        route.insert_str_key(
37024            KUBE_KEY_KIND,
37025            serde_yaml::Value::String(GATEWAY_API_KIND_HTTP_ROUTE.into()),
37026        );
37027        let docs = vec![
37028            serde_yaml::Value::Mapping(gateway),
37029            serde_yaml::Value::Mapping(route),
37030        ];
37031
37032        // Lifted navigator agrees with the inline combinator chain
37033        // on every existing member of the multi-doc slice.
37034        assert_eq!(
37035            find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY),
37036            docs.iter()
37037                .find(|d| kube_kind_is(d, GATEWAY_API_KIND_GATEWAY)),
37038        );
37039        assert_eq!(
37040            find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE),
37041            docs.iter()
37042                .find(|d| kube_kind_is(d, GATEWAY_API_KIND_HTTP_ROUTE)),
37043        );
37044
37045        // And on the miss path: absent kind → None, matching the
37046        // inline `.find` short-circuit that consumer sites rely on
37047        // to distinguish "no such CR in this emission" from "wrong
37048        // shape" in their `.unwrap()` / `.expect(...)` follow-ups.
37049        assert_eq!(find_by_kind(&docs, CILIUM_KIND_NETWORK_POLICY), None);
37050        let empty: Vec<serde_yaml::Value> = Vec::new();
37051        assert_eq!(find_by_kind(&empty, GATEWAY_API_KIND_GATEWAY), None);
37052    }
37053
37054    #[test]
37055    fn find_by_kind_returns_first_match_on_duplicate_kind() {
37056        // Order-preservation pin: the lifted navigator returns the
37057        // first document of the matching kind (the same short-
37058        // circuit `Iterator::find` exposes). Multi-doc mesh
37059        // emissions never carry two documents of the same kind at
37060        // V0 (`gateway_routes` emits exactly one `Gateway` + one
37061        // `HTTPRoute` per Aplicacao), but the M4 cross-cluster
37062        // fan-out will (one `HelmRelease` per cluster). Pinning the
37063        // first-match contract keeps the M4 caller-side "the first
37064        // hit is the primary" convention aligned with the helper's
37065        // combinator half.
37066        let mut gateway_a = serde_yaml::Mapping::new();
37067        gateway_a.insert_str_key(
37068            KUBE_KEY_KIND,
37069            serde_yaml::Value::String(GATEWAY_API_KIND_GATEWAY.into()),
37070        );
37071        let mut meta_a = serde_yaml::Mapping::new();
37072        meta_a.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("primary".into()));
37073        gateway_a.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(meta_a));
37074        let mut gateway_b = serde_yaml::Mapping::new();
37075        gateway_b.insert_str_key(
37076            KUBE_KEY_KIND,
37077            serde_yaml::Value::String(GATEWAY_API_KIND_GATEWAY.into()),
37078        );
37079        let mut meta_b = serde_yaml::Mapping::new();
37080        meta_b.insert_str_key(KUBE_KEY_NAME, serde_yaml::Value::String("secondary".into()));
37081        gateway_b.insert_str_key(KUBE_KEY_METADATA, serde_yaml::Value::Mapping(meta_b));
37082        let docs = vec![
37083            serde_yaml::Value::Mapping(gateway_a),
37084            serde_yaml::Value::Mapping(gateway_b),
37085        ];
37086
37087        let first = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).unwrap();
37088        assert_eq!(
37089            kube_metadata_str_field(first, KUBE_KEY_NAME),
37090            Some("primary"),
37091        );
37092    }
37093
37094    // ── contrato-edge-label + cilium-network-policy-name lifts ──────────
37095
37096    #[test]
37097    fn contrato_edge_label_separator_pin() {
37098        // Load-bearing byte-string pin: the M3 `:contratos`
37099        // edge-direction separator every caixa-mesh emitter that
37100        // encodes a typed edge as a K8s-name-shaped scalar reads from.
37101        // Any future rebrand (e.g. `-to-` → `_to_`) lands here as a
37102        // one-const edit; the peer `contrato_edge_label` /
37103        // `cilium_network_policy_name` composers pick up the new
37104        // encoding by construction. A drift on this const would silently
37105        // split the CNP `metadata.name` from its own
37106        // `metadata.labels.pleme.pleme.io/contrato` value, orphaning
37107        // every operator-side grep-by-label query far from the source
37108        // caixa.lisp.
37109        assert_eq!(CONTRATO_EDGE_LABEL_SEPARATOR, "-to-");
37110    }
37111
37112    #[test]
37113    fn contrato_edge_label_matches_inline_de_to_para_encoding() {
37114        // Byte-shape pin: the composer produces the same
37115        // `format!("{de}-to-{para}")` byte-string every caixa-mesh
37116        // per-`(:de, :para)` `CiliumNetworkPolicy` emitter previously
37117        // inlined at its `labels.insert(LABEL_CONTRATO, …)` call. So a
37118        // future rewire of the composer's internals (multi-hop typed
37119        // edges once the M4 per-edge WIT registry lands, unicode
37120        // arrow-shape rebrand for operator display) reaches every
37121        // consumer through one canonical function-pointer edit.
37122        assert_eq!(contrato_edge_label("cart", "catalog"), "cart-to-catalog");
37123        assert_eq!(contrato_edge_label("cart", "payment"), "cart-to-payment");
37124    }
37125
37126    #[test]
37127    fn contrato_edge_label_threads_separator_between_de_and_para() {
37128        // Composition pin: the composer's shape is
37129        // `de + CONTRATO_EDGE_LABEL_SEPARATOR + para`, so a future
37130        // separator rebrand at [`CONTRATO_EDGE_LABEL_SEPARATOR`]
37131        // reaches the composer through one const-edit and every
37132        // consumer picks up the new encoding by construction. Pin the
37133        // structural equation (not just the byte value) so a future
37134        // reorder of the composer's `format!` argument list (a
37135        // `format!("{para}-{sep}-{de}")` typo mid-refactor) fires here
37136        // rather than silently emitting reversed-direction CNP labels.
37137        let de = "svc-a";
37138        let para = "svc-b";
37139        assert_eq!(
37140            contrato_edge_label(de, para),
37141            format!("{de}{CONTRATO_EDGE_LABEL_SEPARATOR}{para}"),
37142        );
37143    }
37144
37145    #[test]
37146    fn cilium_network_policy_name_matches_inline_aplicacao_de_to_para_encoding() {
37147        // Byte-shape pin: the composer produces the same
37148        // `format!("{aplicacao}-{de}-to-{para}")` byte-string every
37149        // caixa-mesh `cilium_network_policies` per-`(:de, :para)`
37150        // group's `kube_resource_skeleton` `name:` argument previously
37151        // inlined. So a future rewire of the composer's internals
37152        // reaches the CNP renderer through one canonical function-
37153        // pointer edit rather than a coordinated two-site rewrite of
37154        // the [`LABEL_CONTRATO`] labels.insert(...) call and the CNP
37155        // name argument.
37156        assert_eq!(
37157            cilium_network_policy_name("checkout", "cart", "catalog"),
37158            "checkout-cart-to-catalog",
37159        );
37160        assert_eq!(
37161            cilium_network_policy_name("checkout", "cart", "payment"),
37162            "checkout-cart-to-payment",
37163        );
37164    }
37165
37166    #[test]
37167    fn cilium_network_policy_name_composes_on_contrato_edge_label() {
37168        // Composition pin: the CNP name is the parent Aplicacao's
37169        // `:nome` joined to the contrato-edge-label by a canonical `-`
37170        // separator (`format!("{aplicacao}-{edge}")`), so the two
37171        // writer-side helpers close the canonical
37172        // `(LABEL_CONTRATO-value, metadata.name)` per-CNP identity
37173        // pair on one shared edge-encoding source of truth
37174        // ([`CONTRATO_EDGE_LABEL_SEPARATOR`]). Pin the structural
37175        // equation so a future refactor of either composer's internals
37176        // that accidentally desynchronizes the two (a CNP-name
37177        // rebrand landing on `format!("{aplicacao}_{edge}")` while
37178        // the label-value composer stays on `{de}-to-{para}`, or a
37179        // label-composer rebrand landing on `->` while the CNP-name
37180        // composer stays on `-to-`) fires here rather than silently
37181        // orphaning every operator-side grep-by-label query at apply
37182        // time.
37183        let aplicacao = "checkout";
37184        let de = "cart";
37185        let para = "catalog";
37186        let edge = contrato_edge_label(de, para);
37187        assert_eq!(
37188            cilium_network_policy_name(aplicacao, de, para),
37189            format!("{aplicacao}-{edge}"),
37190        );
37191    }
37192
37193    // ── gateway-api-http-route-name lift ────────────────────────────────
37194
37195    #[test]
37196    fn gateway_api_http_route_name_matches_inline_aplicacao_para_encoding() {
37197        // Byte-shape pin: the composer produces the same
37198        // `format!("{aplicacao}-{para}")` byte-string the caixa-mesh
37199        // `gateway_routes` per-`:entrada` `kube_resource_skeleton`
37200        // `name:` argument previously inlined as
37201        // `format!("{}-{}", caixa.nome, entrada.para)`. So a future
37202        // rewire of the composer's internals reaches the HTTPRoute
37203        // renderer through one canonical function-pointer edit rather
37204        // than a hand-agreement between the emitter and every
37205        // test-side probe pinning the expected `<aplicacao>-<para>`
37206        // byte-shape at the HTTPRoute `metadata.name` axis.
37207        assert_eq!(
37208            gateway_api_http_route_name("checkout", "cart"),
37209            "checkout-cart",
37210        );
37211        assert_eq!(gateway_api_http_route_name("orders", "cart"), "orders-cart",);
37212    }
37213
37214    #[test]
37215    fn rendered_file_carries_path_and_contents_fields() {
37216        // Field-shape pin: the canonical [`RenderedFile`] every
37217        // per-target `caixa-<target>` renderer's per-artifact leaf
37218        // resolves through carries exactly the `(path, contents)` pair
37219        // the prior per-crate `BundleFile { path: PathBuf, contents:
37220        // String }` (`caixa-flux`) / `ChartFile { path: PathBuf,
37221        // contents: String }` (`caixa-helm`) clones each carried
37222        // verbatim. A future refactor that adds a per-artifact
37223        // hash / provenance / write-mode discriminator on the record
37224        // must land at the canonical struct definition (this file) —
37225        // the two type aliases at `caixa-flux::BundleFile` /
37226        // `caixa-helm::ChartFile` re-export the canonical unchanged, so
37227        // an addition here reaches both per-target renderers at once,
37228        // and a struct-literal drift that inlines the pre-lift shape
37229        // at either alias trips this pin at caixa-core build time
37230        // rather than surfacing as a divergent per-target renderer's
37231        // record shape far from the source.
37232        let f = RenderedFile {
37233            path: PathBuf::from("Chart.yaml"),
37234            contents: "apiVersion: v2\n".to_string(),
37235        };
37236        assert_eq!(f.path, PathBuf::from("Chart.yaml"));
37237        assert_eq!(f.contents, "apiVersion: v2\n");
37238    }
37239
37240    #[test]
37241    fn rendered_file_derives_pattern_pin() {
37242        // Derive-shape pin: the canonical [`RenderedFile`] carries the
37243        // `Debug + Clone + PartialEq + Eq` derive tuple the two per-
37244        // renderer clones (`caixa-flux::BundleFile` /
37245        // `caixa-helm::ChartFile`) each carried verbatim before the
37246        // lift. `Clone::clone` returns a byte-equal record + the
37247        // `PartialEq::eq` impl returns `true` on the round-trip; a
37248        // future refactor that drops one of the four derives (say,
37249        // removes `PartialEq` on a per-artifact-hash addition) trips
37250        // this pin at caixa-core build time and surfaces the
37251        // per-alias downstream `assert_eq!(bundle_file_a,
37252        // bundle_file_b)` / `assert_eq!(chart_file_a, chart_file_b)`
37253        // navigators in `caixa-flux` / `caixa-helm` — every
37254        // per-alias derive-fed navigator threads through this
37255        // canonical derive tuple by construction.
37256        let f = RenderedFile {
37257            path: PathBuf::from("values.yaml"),
37258            contents: "pleme-computeunit:\n  enabled: false\n".to_string(),
37259        };
37260        let clone = f.clone();
37261        assert_eq!(f, clone);
37262        let dbg = format!("{f:?}");
37263        assert!(
37264            dbg.contains("RenderedFile"),
37265            "Debug output must name the canonical type, got: {dbg:?}",
37266        );
37267    }
37268
37269    #[test]
37270    fn rendered_file_new_matches_struct_literal_shape() {
37271        // Constructor pin: [`RenderedFile::new(FILENAME, contents)`]
37272        // (the canonical lifted `impl Into<PathBuf>` / `impl Into<String>`
37273        // inherent constructor every per-target renderer's per-artifact
37274        // leaf now routes through) produces the byte-identical record
37275        // the six prior inline struct-literal call sites (three
37276        // per-artifact leaves in
37277        // [`caixa_helm::render_chart_for_servico_with`],
37278        // three per-CR leaves in [`caixa_flux::cluster_bundle`]) each
37279        // open-coded as `<Xxx>File { path: PathBuf::from(FILENAME_CONST),
37280        // contents: <body> }`. Pin the equation on a
37281        // `HELM_VALUES_YAML_FILENAME`-shaped input so a future rebrand
37282        // of the constructor's internals (a per-artifact hash /
37283        // provenance field addition, an
37284        // [`is_sandboxed_relative_path`] check at construction time
37285        // once per-cluster-writer sandboxing lands) fires here rather
37286        // than silently splitting the per-target renderer's per-CR
37287        // record shape from the substrate-canonical `(path, contents)`
37288        // pair at the caixa-core canonical.
37289        let via_new = RenderedFile::new(HELM_VALUES_YAML_FILENAME, "pleme-computeunit:\n");
37290        let via_literal = RenderedFile {
37291            path: PathBuf::from(HELM_VALUES_YAML_FILENAME),
37292            contents: "pleme-computeunit:\n".to_string(),
37293        };
37294        assert_eq!(via_new, via_literal);
37295        // Peer path-side pin: `impl Into<PathBuf>` accepts a `PathBuf`
37296        // directly (the future per-target renderer surface where the
37297        // path is composed from author input rather than picked from a
37298        // substrate-canonical `&'static str` filename constant) —
37299        // exercised so a drift onto a stricter `&str`-only bound
37300        // trips this pin at caixa-core build time rather than at the
37301        // first per-target renderer that reaches for the wider bound.
37302        let via_new_from_pathbuf = RenderedFile::new(
37303            PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME),
37304            String::from("kind: HelmRelease\n"),
37305        );
37306        assert_eq!(
37307            via_new_from_pathbuf.path,
37308            PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME),
37309        );
37310        assert_eq!(via_new_from_pathbuf.contents, "kind: HelmRelease\n");
37311    }
37312
37313    #[test]
37314    fn gateway_api_http_route_name_composes_on_canonical_dash_separator() {
37315        // Composition pin: the HTTPRoute `metadata.name` is the parent
37316        // Aplicacao's `:nome` joined to the `:entrada :para`
37317        // destination Servico's `:nome` by a canonical `-` separator
37318        // (`format!("{aplicacao}-{para}")`) — the same
37319        // "aplicacao-prefixed sub-identity" discipline the peer
37320        // [`cilium_network_policy_name`] composer materializes on the
37321        // sibling per-CR K8s-name-shaped-identity-scalar axis
37322        // ([`format!("{aplicacao}-{edge}")`]). Pin the structural
37323        // equation so a future refactor of either composer's internals
37324        // that accidentally desynchronizes the two (an HTTPRoute-name
37325        // rebrand landing on `format!("{aplicacao}.{para}")` while
37326        // the CNP-name composer stays on `{aplicacao}-{edge}`, or a
37327        // per-Aplicacao-K8s-CR-name shared-separator rebrand landing
37328        // on the CNP-name composer without a coordinated edit here)
37329        // fires here rather than silently splitting the two per-CR
37330        // name-encoding axes across the caixa-mesh renderer.
37331        let aplicacao = "checkout";
37332        let para = "cart";
37333        assert_eq!(
37334            gateway_api_http_route_name(aplicacao, para),
37335            format!("{aplicacao}-{para}"),
37336        );
37337    }
37338}