caixa_flux/lib.rs
1//! caixa-flux — typed renderer that emits the FluxCD-side fragments a
2//! caixa Servico needs in the cluster's GitOps tree.
3//!
4//! Same naming convention as [`caixa_helm`] (renders per-program Helm
5//! charts) and [`caixa_flake`] (renders flake.nix): `caixa-<target>` =
6//! "Rust crate that takes a typed [`Caixa`] and emits the canonical
7//! source for `<target>`".
8//!
9//! ## Two paths, two surfaces
10//!
11//! Per `theory/META-FRAMEWORK.md` §I, two equally-canonical ways exist
12//! to deploy a caixa Servico:
13//!
14//! 1. **Aggregator path** ([`programs_yaml_entry`]) — the cluster has
15//! exactly one `lareira-fleet-programs` HelmRelease whose values
16//! contain a `programs:` array. Adding a Servico = adding one entry
17//! to that array. **Higher leverage** — one HelmRelease handles the
18//! whole fleet's worth of caixas, fewer reconciler events, simpler
19//! cluster surface. This is what `feira deploy` uses by default.
20//!
21//! 2. **Bundle path** ([`cluster_bundle`]) — emit a fresh `GitRepository`
22//! + `HelmRelease` + `Kustomization` trio for the caixa's own per-
23//! program chart (rendered by `caixa-helm`). Used for one-off /
24//! isolated services where the aggregator overhead is undesirable
25//! (e.g. alpha workloads with non-standard images, breakglass tooling).
26//!
27//! ## V0 contract
28//!
29//! ```rust,ignore
30//! use caixa_core::Caixa;
31//! use caixa_flux::programs_yaml_entry;
32//!
33//! let caixa = Caixa::from_lisp(src)?;
34//! let cu_yaml: serde_yaml::Value =
35//! serde_yaml::from_str(std::fs::read_to_string("servicos/hello-rio.computeunit.yaml")?)?;
36//! let entry: serde_yaml::Value = programs_yaml_entry(&caixa, &cu_yaml)?;
37//! // → { name: hello-rio, namespace: tatara-system, module: { source: ... }, ... }
38//! ```
39//!
40//! ## What this is NOT
41//!
42//! - Not a Flux CLI wrapper — bytes only.
43//! - Not the operator deploy bundle — that lives in `pleme-io/caixa/operator-flux/`.
44//! - Not an installer — `feira deploy` orchestrates the I/O of writing
45//! to a GitOps repo + opening a PR.
46
47#![allow(clippy::module_name_repetitions)]
48
49use caixa_core::{Caixa, MappingExt, kube_metadata_str_field, lareira_chart_name};
50use serde::{Deserialize, Serialize};
51use thiserror::Error;
52
53/// Errors caixa-flux can raise.
54#[derive(Debug, Error)]
55pub enum Error {
56 /// The caixa's `:kind` doesn't match what `caixa-flux` targets
57 /// (this renderer only emits `programs.yaml` entries +
58 /// `GitRepository`/`HelmRelease`/`Kustomization` bundles for
59 /// `:kind Servico`). Lifted from a prior `NotAServico(CaixaKind)`
60 /// arm to wrap [`caixa_core::KindMismatch`] so the diagnostic
61 /// names the offending caixa's `:nome` (not just its kind),
62 /// shared verbatim with `caixa-helm` and `caixa-mesh`.
63 #[error("{0}")]
64 NotAServico(#[from] caixa_core::KindMismatch),
65 /// The caixa's `:servicos` list doesn't carry exactly one entry —
66 /// the V0 contract every Servico-kind caixa satisfies (one
67 /// ComputeUnit YAML pointer per Servico, matching the one
68 /// programs.yaml entry / cluster bundle this renderer emits).
69 /// Lifted from a prior `UnsupportedServicoCount(usize)` arm to
70 /// wrap [`caixa_core::ServicoCountMismatch`] so the diagnostic
71 /// names the offending caixa's `:nome` (not just the count),
72 /// shared verbatim with `caixa-helm` (the peer per-Servico
73 /// renderer running the same V0 invariant on the
74 /// `lareira-<nome>` chart-dir axis).
75 #[error("{0}")]
76 UnsupportedServicoCount(#[from] caixa_core::ServicoCountMismatch),
77 #[error("computeunit yaml missing required field: {0}")]
78 MissingField(&'static str),
79 #[error("yaml: {0}")]
80 Yaml(#[from] serde_yaml::Error),
81 #[error("render: {0}")]
82 Render(#[from] caixa_core::RenderError),
83}
84
85/// Default cluster-wide namespace for caixa Servicos when the
86/// computeunit doesn't pin its own. Re-export of the canonical
87/// [`caixa_core::DEFAULT_NAMESPACE`] so the namespace string lives in
88/// exactly one place across every renderer — caixa-flux's
89/// programs.yaml / GitRepository / HelmRelease / Kustomization
90/// emitters and caixa-mesh's programs fan-out / CiliumNetworkPolicy /
91/// Gateway / HTTPRoute emitters now consult the same `&'static str`,
92/// so a future per-cluster-namespace rebrand is a one-line edit on
93/// the canonical [`caixa_core::DEFAULT_NAMESPACE`] declaration, not a
94/// coordinated rewrite across this crate, caixa-mesh, and every
95/// future per-target renderer the substrate adds.
96pub use caixa_core::DEFAULT_NAMESPACE;
97
98/// Canonical Flux v2 `spec.interval` reconcile-poll cadence default the
99/// substrate seeds into every per-caixa `cluster_bundle` CR triplet.
100/// Re-export of the canonical [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`]
101/// so the Flux v2 controller-side reconcile-cadence default scalar-value
102/// string lives in exactly one place across every caixa renderer —
103/// [`ClusterBundleOpts::for_caixa`]'s per-caixa default seed (the sole
104/// production-code site the prior inline `"10m"` scalar-value literal sat
105/// at, seeding the [`ClusterBundleOpts::interval`] field that
106/// [`cluster_bundle`]'s three per-CR format-string templates thread
107/// through their [`FLUX_KEY_INTERVAL`]-keyed `spec.interval` axis
108/// verbatim) now consults the same `&'static str`, so a future substrate-
109/// side reconcile-cadence migration (`"10m"` → `"5m"` on lower-latency-
110/// poll optimizations, `"10m"` → `"15m"` on cost-optimized clusters where
111/// per-CR source-controller poll cost outweighs reconcile-freshness
112/// gains — coordinated with the upstream Flux v2 project's per-controller
113/// tuning cycle) is a one-line edit on the canonical
114/// [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] declaration, not a
115/// coordinated rewrite across the [`ClusterBundleOpts`] default seed and
116/// every future per-target renderer the substrate adds. Pairs with the
117/// sibling [`FLUX_KEY_INTERVAL`] re-export on the same per-CR
118/// `spec.interval` scalar-axis — the key half of the per-CR scalar-key/
119/// scalar-value pair lives at [`FLUX_KEY_INTERVAL`], the value half's
120/// substrate-side default seed lives here. Same shape as the sibling
121/// [`caixa_core::DEFAULT_NAMESPACE`] / [`caixa_core::DEFAULT_LIBRARY_NAME`]
122/// / [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] /
123/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] re-exports on the peer
124/// canonical-substrate-default-load-bearing-scalar surface.
125pub use caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL;
126
127/// Canonical Flux v2 `HelmRelease.spec.chart.spec.chart` per-CR chart-
128/// directory-in-GitRepository-source sub-path default the substrate seeds
129/// into every per-caixa `helmrelease.yaml` document. Re-export of the
130/// canonical [`caixa_core::DEFAULT_FLUX_CHART_SOURCE_SUBPATH`] so the
131/// Flux v2 helm-controller-side per-CR chart-directory-in-git-source
132/// default scalar-value lives in exactly one place across every caixa
133/// renderer — [`ClusterBundleOpts::for_caixa`]'s per-caixa default seed
134/// (the sole production-code site the prior inline `"chart".into()`
135/// scalar-value literal sat at, seeding the [`ClusterBundleOpts::chart_path`]
136/// field that [`cluster_bundle`]'s `helmrelease.yaml` format-string
137/// template threads through its [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`]-
138/// keyed `spec.chart.spec.chart` axis verbatim) now consults the same
139/// `&'static str`, so a future substrate-side chart-directory-in-git-
140/// source rebrand (`"chart"` → `"charts"` once a per-caixa multi-chart
141/// layout lands and the substrate publishes N sibling `lareira-<nome>/`
142/// charts under one git repository, `"chart"` → `"helm"` on a cross-
143/// language convention alignment with sibling wasm-runtime substrates,
144/// `"chart"` → `"deploy"` on a per-caixa-deploy-directory naming
145/// migration) is a one-line edit on the canonical
146/// [`caixa_core::DEFAULT_FLUX_CHART_SOURCE_SUBPATH`] declaration, not a
147/// coordinated rewrite across the [`ClusterBundleOpts`] default seed and
148/// every future per-target renderer the substrate adds. Pairs with the
149/// sibling [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`] re-export on the same
150/// per-CR `spec.chart.spec.chart` scalar-axis — the key half of the per-
151/// CR scalar-key/scalar-value pair lives at
152/// [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`], the value half's substrate-side
153/// default seed lives here. Same shape as the sibling
154/// [`caixa_core::DEFAULT_NAMESPACE`] / [`caixa_core::DEFAULT_LIBRARY_NAME`]
155/// / [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] /
156/// [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] /
157/// [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] /
158/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] re-exports on the peer
159/// canonical-substrate-default-load-bearing-scalar surface.
160pub use caixa_core::DEFAULT_FLUX_CHART_SOURCE_SUBPATH;
161
162/// Canonical Flux v2 `HelmRelease.spec.{install,upgrade}.remediation.retries`
163/// bounded retry-count default the substrate seeds into every per-caixa
164/// `helmrelease.yaml` document. Re-export of the canonical
165/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] so the
166/// Flux v2 helm-controller-side remediation-retries default scalar-value
167/// lives in exactly one place across every caixa renderer —
168/// [`cluster_bundle`]'s `helmrelease.yaml` format-string template's two
169/// production-code retry-cap sites (the prior inline `retries: 3`
170/// scalar-value literal under the `install.remediation` sub-block + the
171/// second inline `retries: 3` scalar-value literal under the
172/// `upgrade.remediation` sub-block) now both consume the same `u32` at
173/// emit time through one `{retries_default}` named-arg interpolation, so
174/// a future substrate-side retry-ceiling migration (`3` → `5` once per-
175/// caixa idempotency invariants tighten, `3` → `1` on hardened per-caixa
176/// pipelines where a failed apply should escalate to operator-attention
177/// rather than mask under further retries — coordinated with the
178/// upstream Flux v2 project's per-controller tuning cycle) is a one-line
179/// edit on the canonical
180/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]
181/// declaration, not a coordinated rewrite across the two per-CR
182/// remediation-retries sites. Before this lift the two axes carried
183/// independently-inlined `retries: 3` literals in the sibling
184/// `install.remediation.retries` / `upgrade.remediation.retries`
185/// positions of the [`cluster_bundle`] `helmrelease.yaml` format-string
186/// template — any future retry-ceiling migration on one axis without a
187/// coordinated edit on the other would have silently split the
188/// substrate's canonical retry-ceiling between the install-path (first-
189/// time chart applies) and the upgrade-path (every subsequent per-
190/// caixa-version re-apply the same `HelmRelease` gates), with no field
191/// naming the ceiling-drift root cause. Pairs with the sibling
192/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] re-export on the same canonical-
193/// Flux-v2-per-CR-substrate-default surface — the reconcile-poll cadence
194/// default names how often the helm-controller re-evaluates per-CR
195/// desired state, and this retry-cap names how many times a per-
196/// evaluation Helm action is allowed to fail-and-retry before it stops.
197/// Same shape as the sibling [`caixa_core::DEFAULT_NAMESPACE`] /
198/// [`caixa_core::DEFAULT_LIBRARY_NAME`] /
199/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] /
200/// [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] /
201/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] re-exports on the peer
202/// canonical-substrate-default-load-bearing-scalar surface.
203pub use caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT;
204
205/// Canonical Flux v2 `HelmRelease.spec.{install,upgrade}.remediation.retries`
206/// leaf scalar-key — re-export of the canonical
207/// [`caixa_core::FLUX_HELMRELEASE_KEY_RETRIES`] so the Flux v2
208/// helm-controller-side per-CR remediation-retries leaf-scalar-key lives
209/// in exactly one place across every caixa renderer. Peer to the sibling
210/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
211/// value half of the same `(leaf-key, scalar-value)` per-path retry-cap
212/// declaration pair — extends the drift-closing discipline the scalar-
213/// value lift established from the value the leaf holds onto the leaf-
214/// key itself. Two production emit sites (this crate's [`cluster_bundle`]
215/// `helmrelease.yaml` format-string template's install-path retry-cap
216/// leaf under the [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]-valued
217/// sub-block + the sibling upgrade-path retry-cap leaf under the same
218/// scalar-value, both threading the same `&'static str` through a
219/// `{retries_key}` named-arg interpolation) plus two test-fixture
220/// navigation sites in `mod tests` (the install-path
221/// [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
222/// pin's `.get("retries")` probe + the sibling upgrade-path
223/// [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
224/// pin's peer probe) now consult the same `&'static str`. Until this
225/// lift landed the axis carried four inline `retries` literals across
226/// the two production emit sites and the two test-fixture navigation
227/// sites; a future hypothetical Flux v3 rename (`attempts` /
228/// `maxRetries` / `retryCount`) on any production-emit site without a
229/// coordinated edit on the sibling navigation sites would have silently
230/// stripped the retry-cap declaration from the emitted `remediation:`
231/// sub-block, letting the helm-controller fall back to the Flux v2
232/// upstream default rather than the substrate's chosen ceiling with no
233/// diagnostic naming the leaf-key-drift root cause. Same shape as the
234/// sibling [`FLUX_KEY_SOURCE_REF`] (236ef01) / [`FLUX_KEY_CHART`] /
235/// [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
236/// [`FLUX_KEY_HEALTH_CHECKS`] lifts on the peer per-CR container-axis-
237/// key surface — extends the discipline from the container-axis keys
238/// that nest per-CR sub-blocks onto a leaf-scalar-key at the bottom of
239/// a two-level nested per-path retry-cap declaration.
240pub use caixa_core::FLUX_HELMRELEASE_KEY_RETRIES;
241
242/// Canonical Flux v2 `HelmRelease.spec.{install,upgrade}.remediation`
243/// sub-container-axis-key — re-export of the canonical
244/// [`caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATION`] so the Flux v2
245/// helm-controller-side per-CR remediation sub-container-axis-key lives
246/// in exactly one place across every caixa renderer. Peer to the sibling
247/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key half + the
248/// sibling [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae)
249/// scalar-value half of the same
250/// `(container-axis-key, leaf-scalar-key, scalar-value)` per-path retry-
251/// cap declaration triple — closes the parent-container-axis-key axis on
252/// the same per-path retry-cap declaration, so all three halves now live
253/// in one place. Two production emit sites (this crate's
254/// [`cluster_bundle`] `helmrelease.yaml` format-string template's
255/// install-path remediation sub-block-header + the sibling upgrade-path
256/// remediation sub-block-header, both threading the same `&'static str`
257/// through a `{remediation_key}` named-arg interpolation) plus two test-
258/// fixture navigation sites in `mod tests` (the install-path
259/// [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
260/// pin's `.get(FLUX_HELMRELEASE_KEY_REMEDIATION)` probe + the sibling
261/// upgrade-path
262/// [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
263/// pin's peer probe) now consult the same `&'static str`. Until this
264/// lift landed the axis carried four inline `remediation` literals across
265/// the two production emit sites and the two test-fixture navigation
266/// sites; a future hypothetical Flux v3 rename (`recovery` /
267/// `retryPolicy` / `errorHandling`) on any production-emit site without
268/// a coordinated edit on the sibling navigation sites would have
269/// silently stripped the whole per-path remediation sub-block from the
270/// emitted `HelmRelease` CR, letting the helm-controller fall back to
271/// the Flux v2 upstream defaults for the whole remediation surface
272/// rather than the substrate's chosen ceiling with no diagnostic naming
273/// the sub-container-key-drift root cause. Same shape as the sibling
274/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key half plus
275/// the peer [`FLUX_KEY_SOURCE_REF`] (236ef01) / [`FLUX_KEY_CHART`] /
276/// [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
277/// [`FLUX_KEY_HEALTH_CHECKS`] container-axis-key lifts on the peer per-
278/// CR container-axis-key surface — extends the discipline from the
279/// leaf-scalar-key at the bottom of the two-level nested per-path
280/// retry-cap declaration onto the sub-container-axis-key one level up.
281pub use caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATION;
282
283/// Canonical Flux v2 `HelmRelease.spec.install` per-CR helm-action-phase
284/// discriminator parent-container-axis-key — re-export of the canonical
285/// [`caixa_core::FLUX_HELMRELEASE_KEY_INSTALL`] so the Flux v2 helm-
286/// controller-side per-CR install-path phase-discriminator parent-
287/// container-axis-key lives in exactly one place across every caixa
288/// renderer. Pairs with the sibling [`FLUX_HELMRELEASE_KEY_UPGRADE`]
289/// per-CR helm-action-phase discriminator parent-container-axis-key on
290/// the peer per-CR upgrade-path phase. Peer to the sibling
291/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key
292/// hosted beneath both parent-container-axis-keys +
293/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key +
294/// [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) scalar-
295/// value halves of the same `(parent-container-key, sub-container-key,
296/// leaf-key, scalar-value)` per-path retry-cap declaration quartet —
297/// closes the parent-container-axis-key axis on the same per-path retry-
298/// cap declaration quartet, so all four halves now live in one place.
299/// One production emit site (this crate's [`cluster_bundle`]
300/// `helmrelease.yaml` format-string template's install-path sub-block-
301/// header, threading the same `&'static str` through a new
302/// `{install_key}` named-arg interpolation) plus one test-fixture
303/// navigation site in `mod tests` (the install-path
304/// [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
305/// pin's `.get(FLUX_HELMRELEASE_KEY_INSTALL)` probe) now consult the
306/// same `&'static str`. Until this lift landed the axis carried two
307/// inline `install` literals across the one production emit site and
308/// the one test-fixture navigation site; a future hypothetical Flux v3
309/// rename (`initialize` / `apply` / `create` / `first-run`) on the
310/// production-emit site without a coordinated edit on the sibling
311/// navigation site would have silently stripped the whole install-path
312/// per-CR phase block from the emitted `HelmRelease` CR, letting the
313/// helm-controller fall back to the Flux v2 upstream defaults for the
314/// whole install-path phase surface (the `createNamespace: true` seeder
315/// never fires, the per-CR retry-cap ceiling silently drops off the
316/// emitted document) rather than the substrate's chosen per-CR install-
317/// path knob-set with no diagnostic naming the phase-discriminator-drift
318/// root cause. Same shape as the sibling
319/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
320/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key + the peer
321/// [`FLUX_KEY_SOURCE_REF`] (236ef01) / [`FLUX_KEY_CHART`] /
322/// [`FLUX_KEY_VALUES`] / [`FLUX_KEY_INTERVAL`] /
323/// [`FLUX_KEY_HEALTH_CHECKS`] container-axis-key lifts on the peer per-
324/// CR container-axis-key surface — extends the discipline from the sub-
325/// container-axis-key one level up onto the parent-container-axis-key
326/// hosting it, so the four-level nested `spec.install.remediation
327/// .retries` declaration now resolves through four lifted `&'static str`
328/// / `u32` values.
329pub use caixa_core::FLUX_HELMRELEASE_KEY_INSTALL;
330
331/// Canonical Flux v2 `HelmRelease.spec.upgrade` per-CR helm-action-phase
332/// discriminator parent-container-axis-key — re-export of the canonical
333/// [`caixa_core::FLUX_HELMRELEASE_KEY_UPGRADE`] so the Flux v2 helm-
334/// controller-side per-CR upgrade-path phase-discriminator parent-
335/// container-axis-key lives in exactly one place across every caixa
336/// renderer. Pairs with the sibling [`FLUX_HELMRELEASE_KEY_INSTALL`]
337/// per-CR helm-action-phase discriminator parent-container-axis-key on
338/// the peer per-CR install-path phase. Peer to the sibling
339/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key
340/// hosted beneath both parent-container-axis-keys. One production emit
341/// site (this crate's [`cluster_bundle`] `helmrelease.yaml` format-
342/// string template's upgrade-path sub-block-header, threading the same
343/// `&'static str` through a new `{upgrade_key}` named-arg interpolation)
344/// plus one test-fixture navigation site in `mod tests` (the upgrade-
345/// path
346/// [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
347/// pin's `.get(FLUX_HELMRELEASE_KEY_UPGRADE)` probe) now consult the
348/// same `&'static str`. Until this lift landed the axis carried two
349/// inline `upgrade` literals across the one production emit site and
350/// the one test-fixture navigation site; a future hypothetical Flux v3
351/// rename (`reapply` / `reconcile` / `update` / `promote`) on the
352/// production-emit site without a coordinated edit on the sibling
353/// navigation site would have silently stripped the whole upgrade-path
354/// per-CR phase block from the emitted `HelmRelease` CR, letting the
355/// helm-controller fall back to the Flux v2 upstream defaults for the
356/// whole upgrade-path phase surface (the substrate's
357/// `remediateLastFailure: true` toggle never fires, the per-CR retry-
358/// cap ceiling silently drops off the emitted document) rather than the
359/// substrate's chosen per-CR upgrade-path knob-set with no diagnostic
360/// naming the phase-discriminator-drift root cause. Same shape as the
361/// sibling [`FLUX_HELMRELEASE_KEY_INSTALL`] parent-container-axis-key
362/// on the peer per-CR install-path phase — pairs with the install-path
363/// re-export to close the per-CR helm-action-phase discriminator
364/// parent-container-axis-key pair across both per-CR phases the helm-
365/// controller reconciles between.
366pub use caixa_core::FLUX_HELMRELEASE_KEY_UPGRADE;
367
368/// Canonical Flux v2 `HelmRelease.spec.upgrade.remediation.remediateLastFailure`
369/// upgrade-path-only per-CR remediation-toggle leaf-scalar-key — re-export
370/// of the canonical [`caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`]
371/// so the Flux v2 helm-controller-side upgrade-path per-CR remediation-
372/// toggle leaf-scalar-key lives in exactly one place across every caixa
373/// renderer. Sibling to the peer [`FLUX_HELMRELEASE_KEY_RETRIES`] per-CR
374/// retry-cap leaf-scalar-key at the same per-CR upgrade-path per-CR
375/// remediation sub-container position — closes the
376/// `spec.upgrade.remediation.{retries, remediateLastFailure}` per-path
377/// remediation-block leaf-scalar-key pair the substrate seeds into every
378/// emitted per-caixa `HelmRelease` CR on the upgrade-path per-CR
379/// remediation block. One production emit site (this crate's
380/// [`cluster_bundle`] `helmrelease.yaml` format-string template's
381/// upgrade-path remediation-toggle leaf under the sibling
382/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`]-container-keyed sub-block,
383/// threading the same `&'static str` through a new
384/// `{remediate_last_failure_key}` named-arg interpolation) plus one test-
385/// fixture navigation site in `mod tests` (the upgrade-path
386/// [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
387/// pin's `.get(FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE)` probe) now
388/// consult the same `&'static str`. Until this lift landed the axis
389/// carried the load-bearing `remediateLastFailure` bytes inline at the
390/// one production emit site; a future hypothetical Flux v3 rename
391/// (`rollbackOnFailure` / `remediateOnFailure` / `recoverLastFailure`)
392/// on the production-emit site without a coordinated edit on every
393/// per-renderer consumer the absorption roadmap surfaces (the M4
394/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
395/// `HelmRelease` synthesis) would have silently dropped the substrate's
396/// chosen post-retry-exhaustion rollback semantic from every emitted
397/// per-caixa `HelmRelease` document — the helm-controller would then
398/// leave every terminally-failed upgrade in the failed state without
399/// rolling back to the prior last-known-good release the substrate's
400/// "no chart apply leaves a per-caixa CR in a stalled, unremediated
401/// state" MESH-COMPOSITION.md §V guarantee mandates, with no diagnostic
402/// naming the remediation-toggle-drift root cause far from the source
403/// caixa.lisp / the renderer's format-string template. Same shape as
404/// the sibling [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-
405/// key + the peer [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-
406/// container-axis-key + [`FLUX_HELMRELEASE_KEY_INSTALL`] /
407/// [`FLUX_HELMRELEASE_KEY_UPGRADE`] (7767c26) parent-container-axis-key
408/// pair lifts on the peer per-CR remediation-surface leaf-scalar-key /
409/// container-axis-key surface — extends the discipline from the sibling
410/// retry-cap leaf-scalar-key onto the co-resident remediation-toggle
411/// leaf-scalar-key at the same `spec.upgrade.remediation.*` position.
412pub use caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE;
413
414/// Canonical Flux v2 `HelmRelease.spec.upgrade.remediation.remediateLastFailure`
415/// upgrade-path-only per-CR remediation-toggle scalar-value default the
416/// substrate seeds into every per-caixa `helmrelease.yaml` document at the
417/// paired [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] leaf-scalar-key
418/// axis. Re-export of the canonical
419/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`] so the
420/// Flux v2 helm-controller-side per-CR upgrade-path per-CR post-retry-
421/// exhaustion-rollback-toggle scalar-value default lives in exactly one
422/// place across every caixa renderer — [`cluster_bundle`]'s
423/// `helmrelease.yaml` format-string template's per-CR upgrade-path
424/// remediation-toggle scalar under the [`FLUX_HELMRELEASE_KEY_UPGRADE`]-
425/// keyed sub-block (the sole production-code site the prior inline
426/// `remediateLastFailure: true` scalar-value literal sat at, alongside the
427/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`]-keyed leaf-scalar-key
428/// half of the same `(leaf-key, scalar-value)` pair) now threads the same
429/// `bool` through a `{remediate_last_failure_default}` named-arg
430/// interpolation, so a future substrate-side toggle migration (`true` →
431/// `false` on a per-cluster class where terminally-failed upgrades must
432/// escalate to operator-attention rather than mask under an auto-rollback
433/// pipeline; a per-caixa opt-out slot the ABSORPTION-ROADMAP.md M4 typed-
434/// slot trajectory adds once the substrate grows a `:upgrade
435/// :remediate-last-failure` author-side toggle) is a one-line edit on the
436/// canonical [`caixa_core::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`]
437/// declaration, not a coordinated rewrite across the emit site + every
438/// future per-target renderer the substrate adds. Pairs with the sibling
439/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] re-export on the same
440/// per-CR `spec.upgrade.remediation.remediateLastFailure` scalar-axis —
441/// the key half of the per-CR scalar-key/scalar-value pair lives at
442/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`], the value half's
443/// substrate-side default seed lives here. Same shape as the sibling
444/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) scalar-value default
445/// re-export on the peer per-CR `Kustomization` garbage-collection-toggle
446/// axis — that default names whether the per-CR `Kustomization` reconcile
447/// loop sweeps orphaned resources at all, and this default names whether
448/// the per-CR `HelmRelease` upgrade-path remediation loop rolls back to
449/// the prior last-known-good release once the retry-cap ceiling is
450/// exhausted. Both are substrate-side policy choices the operator
451/// inherits when the per-caixa [`ClusterBundleOpts`] doesn't pin an
452/// override, and both must move together on any coordinated substrate-
453/// side Flux v2 per-CR tuning-cycle promotion. Until this lift landed the
454/// axis carried an inline `true` scalar-value literal at the sole
455/// production-code call site plus the sibling test-fixture navigation
456/// site ([`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
457/// pin's `assert!(remediate_last_failure)` predicate) — two occurrences
458/// of the same load-bearing Flux-v2-per-CR-upgrade-path-remediation-
459/// toggle-scalar-value convention, drift-prone by construction ahead of
460/// the third occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
461/// materializer's per-Aplicacao `HelmRelease` synthesis will surface.
462/// Same shape as the sibling [`caixa_core::DEFAULT_NAMESPACE`] /
463/// [`caixa_core::DEFAULT_LIBRARY_NAME`] /
464/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] /
465/// [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] /
466/// [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] /
467/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] /
468/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] /
469/// [`caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] re-exports on the peer
470/// canonical-substrate-default-load-bearing-scalar surface.
471pub use caixa_core::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT;
472
473/// Canonical Flux v2 `HelmRelease.spec.install.createNamespace` install-path-
474/// only per-CR namespace-seeder-toggle leaf-scalar-key — re-export of the
475/// canonical [`caixa_core::FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] so the
476/// Flux v2 helm-controller-side install-path per-CR namespace-seeder-toggle
477/// leaf-scalar-key lives in exactly one place across every caixa renderer.
478/// Peer to the sibling [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`]
479/// (96581b7) upgrade-path-only per-CR remediation-toggle leaf-scalar-key at
480/// the mirror-symmetric parent-container-axis-key position — closes the
481/// `spec.{install.createNamespace, upgrade.remediation.remediateLastFailure}`
482/// per-path per-CR phase-specific toggle leaf-scalar-key pair the substrate
483/// seeds into every emitted per-caixa `HelmRelease` CR. One production emit
484/// site (this crate's [`cluster_bundle`] `helmrelease.yaml` format-string
485/// template's install-path namespace-seeder-toggle leaf under the sibling
486/// [`FLUX_HELMRELEASE_KEY_INSTALL`]-container-keyed sub-block, threading
487/// the same `&'static str` through a new `{create_namespace_key}` named-
488/// arg interpolation) plus one test-fixture navigation site in `mod tests`
489/// (the install-path
490/// [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
491/// pin's `.get(FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE)` probe) now consult
492/// the same `&'static str`. Until this lift landed the axis carried the
493/// load-bearing `createNamespace` bytes inline at the one production emit
494/// site; a future hypothetical Flux v3 rename (`createTargetNamespace` /
495/// `seedNamespace` / `provisionNamespace`) on the production-emit site
496/// without a coordinated edit on every per-renderer consumer the
497/// absorption roadmap surfaces (the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
498/// CR materializer's per-Aplicacao `HelmRelease` synthesis) would have
499/// silently dropped the substrate's chosen first-apply namespace-seeder
500/// semantic from every emitted per-caixa `HelmRelease` document — the
501/// helm-controller would then refuse every first-time per-caixa chart
502/// apply against a fresh cluster whose target namespace has not been
503/// pre-provisioned by an out-of-band pipeline the substrate's "no per-
504/// caixa Servico apply is blocked on manual namespace preprovisioning"
505/// MESH-COMPOSITION.md §V install-path-fluency guarantee mandates, with no
506/// diagnostic naming the seeder-toggle-drift root cause far from the
507/// source caixa.lisp / the renderer's format-string template. Same shape
508/// as the sibling [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7)
509/// upgrade-path-only per-CR remediation-toggle leaf-scalar-key +
510/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key + peer
511/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key +
512/// [`FLUX_HELMRELEASE_KEY_INSTALL`] / [`FLUX_HELMRELEASE_KEY_UPGRADE`]
513/// (7767c26) parent-container-axis-key pair lifts on the peer per-CR
514/// HelmRelease-spec surface — extends the discipline from the sibling
515/// upgrade-path-only per-CR remediation-toggle onto the mirror install-
516/// path-only per-CR namespace-seeder-toggle at the `spec.install.*`
517/// position mirroring the peer's `spec.upgrade.remediation.*` position.
518pub use caixa_core::FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE;
519
520/// Canonical Flux v2 `HelmRelease.spec.install.createNamespace` install-path-
521/// only per-CR namespace-seeder-toggle scalar-value default the substrate
522/// seeds into every per-caixa `helmrelease.yaml` document at the paired
523/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] leaf-scalar-key axis. Re-
524/// export of the canonical
525/// [`caixa_core::FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`] so the Flux
526/// v2 helm-controller-side per-CR install-path per-CR namespace-seeder-
527/// toggle scalar-value default lives in exactly one place across every
528/// caixa renderer — [`cluster_bundle`]'s `helmrelease.yaml` format-
529/// string template's per-CR install-path namespace-seeder-toggle scalar
530/// under the [`FLUX_HELMRELEASE_KEY_INSTALL`]-keyed sub-block (the sole
531/// production-code site the prior inline `createNamespace: true` scalar-
532/// value literal sat at, alongside the [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`]-
533/// keyed leaf-scalar-key half of the same `(leaf-key, scalar-value)`
534/// pair) now threads the same `bool` through a `{create_namespace_default}`
535/// named-arg interpolation, so a future substrate-side toggle migration
536/// (`true` → `false` on hardened per-cluster classes where namespace
537/// provisioning is an out-of-band operator gate; a per-caixa opt-out
538/// slot the ABSORPTION-ROADMAP.md M4 typed-slot trajectory adds once the
539/// substrate grows a `:install :create-namespace` author-side toggle) is
540/// a one-line edit on the canonical
541/// [`caixa_core::FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`] declaration,
542/// not a coordinated rewrite across the emit site + every future per-
543/// target renderer the substrate adds. Pairs with the sibling
544/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] re-export on the same per-CR
545/// `spec.install.createNamespace` scalar-axis — the key half of the
546/// per-CR scalar-key/scalar-value pair lives at
547/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`], the value half's substrate-
548/// side default seed lives here. Peer with the sibling
549/// [`FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`] mirror-symmetric
550/// upgrade-path-only scalar-value default + the sibling
551/// [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8) scalar-value default
552/// on the peer canonical-Flux-v2-per-CR-substrate-default surface — the
553/// three defaults name the substrate's canonical (install-path
554/// namespace-seeder) / (upgrade-path post-retry-exhaustion rollback) /
555/// (garbage-collection-toggle) toggle triple across the per-caixa
556/// `HelmRelease` and `Kustomization` co-resident CRs. All three are
557/// substrate-side policy choices the operator inherits when the per-
558/// caixa [`ClusterBundleOpts`] doesn't pin an override, and all three
559/// must move together on any coordinated substrate-side Flux v2 per-CR
560/// tuning-cycle promotion. Until this lift landed the axis carried an
561/// inline `true` scalar-value literal at the sole production-code call
562/// site plus the sibling test-fixture navigation site
563/// ([`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
564/// pin's `assert!(create_namespace)` predicate) — two occurrences of the
565/// same load-bearing Flux-v2-per-CR-install-path-namespace-seeder-
566/// toggle-scalar-value convention, drift-prone by construction ahead of
567/// the third occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
568/// materializer's per-Aplicacao `HelmRelease` synthesis will surface.
569/// Same shape as the sibling [`caixa_core::DEFAULT_NAMESPACE`] /
570/// [`caixa_core::DEFAULT_LIBRARY_NAME`] /
571/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] /
572/// [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] /
573/// [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] /
574/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] /
575/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] /
576/// [`caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] /
577/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`]
578/// re-exports on the peer canonical-substrate-default-load-bearing-
579/// scalar surface.
580pub use caixa_core::FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT;
581
582/// Canonical Flux v2 `Kustomization.spec.prune` per-CR garbage-collection-
583/// toggle leaf-scalar-key — re-export of the canonical
584/// [`caixa_core::FLUX_KUSTOMIZATION_KEY_PRUNE`] so the Flux v2 kustomize-
585/// controller-side per-CR garbage-collection-toggle leaf-scalar-key lives
586/// in exactly one place across every caixa renderer. Peer to the sibling
587/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) install-path-only
588/// per-CR namespace-seeder-toggle leaf-scalar-key on the co-resident
589/// per-caixa `HelmRelease` CR — extends the per-CR-toggle leaf-scalar-key
590/// discipline from the co-resident per-caixa `HelmRelease` CR spec surface
591/// onto the co-resident per-caixa `Kustomization` CR spec surface at the
592/// mirror-symmetric top-level `spec.prune` position. One production emit
593/// site (this crate's [`cluster_bundle`] `kustomization.yaml` format-
594/// string template's per-CR garbage-collection-toggle leaf under the
595/// top-level `spec` position, threading the same `&'static str` through a
596/// new `{prune_key}` named-arg interpolation) plus one test-fixture
597/// navigation site in `mod tests` (the per-CR
598/// [`cluster_bundle_kustomization_prune_pins_lifted_true`] pin's
599/// `.get(FLUX_KUSTOMIZATION_KEY_PRUNE)` probe) now consult the same
600/// `&'static str`. Until this lift landed the axis carried the load-
601/// bearing `prune` bytes inline at the one production emit site; a
602/// future hypothetical Flux v3 rename (`garbageCollect` / `sweep` /
603/// `pruneOrphaned` / `deleteOrphans`) on the production-emit site
604/// without a coordinated edit on every per-renderer consumer the
605/// absorption roadmap surfaces (the M4 `mesh.pleme.io/v1alpha1/Aplicacao`
606/// CR materializer's per-Aplicacao `Kustomization` synthesis) would have
607/// silently dropped the substrate's chosen sweep-what-you-removed
608/// semantic from every emitted per-caixa `Kustomization` document — the
609/// kustomize-controller would then leave every per-caixa resource the
610/// source manifest set previously reconciled but no longer carries
611/// dangling in the cluster the substrate's "the cluster's per-caixa live
612/// state converges to the caixa's tatara-lisp source-of-truth on every
613/// reconcile — resources the source no longer carries are swept by the
614/// kustomize-controller, not left dangling" CAIXA-SDLC.md §V author-to-
615/// live-convergence guarantee mandates, with no diagnostic naming the
616/// toggle-drift root cause far from the source caixa.lisp / the
617/// renderer's format-string template. Same shape as the sibling
618/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) install-path-only
619/// per-CR namespace-seeder-toggle leaf-scalar-key +
620/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7) upgrade-
621/// path-only per-CR remediation-toggle leaf-scalar-key +
622/// [`FLUX_HELMRELEASE_KEY_RETRIES`] (a12f9fc) leaf-scalar-key + peer
623/// [`FLUX_HELMRELEASE_KEY_REMEDIATION`] (6fe4e7e) sub-container-axis-key
624/// + [`FLUX_HELMRELEASE_KEY_INSTALL`] / [`FLUX_HELMRELEASE_KEY_UPGRADE`]
625/// (7767c26) parent-container-axis-key pair lifts on the peer per-CR
626/// HelmRelease-spec surface — extends the discipline from the co-
627/// resident per-`HelmRelease`-CR spec surface onto the co-resident per-
628/// `Kustomization`-CR spec surface at the mirror-symmetric top-level
629/// `spec.prune` position.
630pub use caixa_core::FLUX_KUSTOMIZATION_KEY_PRUNE;
631
632/// Canonical Flux v2 `Kustomization.spec.prune` per-CR garbage-collection-
633/// toggle scalar-value default the substrate seeds into every per-caixa
634/// `kustomization.yaml` document at the paired
635/// [`FLUX_KUSTOMIZATION_KEY_PRUNE`] leaf-scalar-key axis. Re-export of
636/// the canonical [`caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] so the
637/// Flux v2 kustomize-controller-side per-CR garbage-collection-toggle
638/// scalar-value default lives in exactly one place across every caixa
639/// renderer — [`cluster_bundle`]'s `kustomization.yaml` format-string
640/// template's per-CR garbage-collection-toggle scalar under the top-level
641/// `spec` position (the sole production-code site the prior inline
642/// `prune: true` scalar-value literal sat at, alongside the
643/// [`FLUX_KUSTOMIZATION_KEY_PRUNE`]-keyed leaf-scalar-key half of the
644/// same `(leaf-key, scalar-value)` pair) now threads the same `bool`
645/// through a `{prune_default}` named-arg interpolation, so a future
646/// substrate-side toggle migration (`true` → `false` on a cluster class
647/// where a human is expected to prune orphaned resources by hand once
648/// per-cluster policy grows an "operator-driven cleanup" mode; a per-
649/// caixa opt-out slot the ABSORPTION-ROADMAP.md M4 typed-slot
650/// trajectory adds once the substrate grows a `:kustomization :prune`
651/// author-side toggle) is a one-line edit on the canonical
652/// [`caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] declaration, not a
653/// coordinated rewrite across the emit site + every future per-target
654/// renderer the substrate adds. Pairs with the sibling
655/// [`FLUX_KUSTOMIZATION_KEY_PRUNE`] re-export on the same per-CR
656/// `spec.prune` scalar-axis — the key half of the per-CR scalar-key /
657/// scalar-value pair lives at [`FLUX_KUSTOMIZATION_KEY_PRUNE`], the
658/// value half's substrate-side default seed lives here. Same shape as
659/// the sibling [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae)
660/// scalar-value default re-export on the peer per-CR HelmRelease
661/// remediation retry-cap axis — that default names the per-path per-CR
662/// remediation retry ceiling, and this default names whether the
663/// per-CR reconcile loop sweeps orphaned resources at all. Both are
664/// substrate-side policy choices the operator inherits when the per-
665/// caixa [`ClusterBundleOpts`] doesn't pin an override, and both must
666/// move together on any coordinated substrate-side Flux v2 per-CR
667/// tuning-cycle promotion. Until this lift landed the axis carried an
668/// inline `true` scalar-value literal at the sole production-code call
669/// site plus the sibling test-fixture navigation site
670/// ([`cluster_bundle_kustomization_prune_pins_lifted_true`] pin's
671/// `assert!(prune)` predicate) — two occurrences of the same load-
672/// bearing Flux-v2-per-CR-garbage-collection-toggle-scalar-value
673/// convention, drift-prone by construction ahead of the third
674/// occurrence the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's
675/// per-Aplicacao `Kustomization` synthesis will surface. Same shape as
676/// the sibling [`caixa_core::DEFAULT_NAMESPACE`] /
677/// [`caixa_core::DEFAULT_LIBRARY_NAME`] /
678/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] /
679/// [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] /
680/// [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] /
681/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] /
682/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]
683/// re-exports on the peer canonical-substrate-default-load-bearing-
684/// scalar surface.
685pub use caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT;
686
687/// Canonical substrate-side default for the
688/// `HelmRelease.spec.values.<library>.enabled` child-chart-enablement
689/// toggle scalar every [`cluster_bundle`]-emitted `helmrelease.yaml`
690/// document seeds under its per-`{library_name}` values-overlay wrap
691/// to force-on the paired [`caixa_core::DEFAULT_LIBRARY_NAME`] child
692/// chart at the per-cluster `HelmRelease`-side apply step — re-export
693/// of the canonical [`caixa_core::CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`]
694/// so the substrate-side child-chart-enablement-toggle scalar-value
695/// default lives in exactly one place across every caixa renderer.
696/// Pairs with the sibling [`caixa_core::HELM_VALUES_KEY_ENABLED`]
697/// leaf-scalar-key half of the `(leaf-key, scalar-value)`
698/// per-values-overlay child-chart-enablement-toggle declaration pair.
699///
700/// Peer with the sibling [`FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`]
701/// (be1904b), [`FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`]
702/// (be1904b), [`FLUX_KUSTOMIZATION_PRUNE_DEFAULT`] (ea857d8), and
703/// [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]
704/// scalar-value defaults on the peer canonical-Flux-v2-per-CR-
705/// substrate-default surface — the four sibling scalar-value defaults
706/// name per-CR toggle-shape axes at the `HelmRelease.spec.install.*` /
707/// `HelmRelease.spec.upgrade.*` / `HelmRelease.spec.upgrade.remediation.retries`
708/// / `Kustomization.spec.prune` sub-block positions, and this scalar-
709/// value default names the child-chart-enablement toggle at the deeper
710/// `HelmRelease.spec.values.<library>.enabled` values-overlay position.
711///
712/// Until this lift landed the axis carried an inline `true` scalar-value
713/// literal at the sole production-code call site (the `{enabled_key}: true`
714/// leaf inside [`cluster_bundle`]'s `helmrelease.yaml` format-string
715/// template's per-`{library_name}` wrap position) plus its paired
716/// test-fixture navigation site's `Some(true)` assertion — two
717/// occurrences of the same load-bearing values-overlay child-chart-
718/// enablement-toggle-scalar-value convention, drift-prone by construction
719/// ahead of the third occurrence the M4
720/// `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-Aplicacao
721/// `HelmRelease` synthesis will surface.
722pub use caixa_core::CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT;
723
724/// Canonical Flux v2 `Kustomization.spec.path` per-CR source-sub-tree
725/// leaf-scalar-key — re-export of the canonical
726/// [`caixa_core::FLUX_KUSTOMIZATION_KEY_PATH`] so the Flux v2 kustomize-
727/// controller-side per-CR source-sub-tree leaf-scalar-key lives in
728/// exactly one place across every caixa renderer. Peer to the sibling
729/// co-resident [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917) per-CR
730/// garbage-collection-toggle leaf-scalar-key on the same top-level
731/// `spec` position of the emitted per-caixa `Kustomization` CR — extends
732/// the per-`Kustomization`-CR-spec leaf-scalar-key discipline from the
733/// co-resident garbage-collection-toggle axis onto the co-resident
734/// source-sub-tree axis at the mirror-symmetric top-level `spec.path`
735/// position. One production emit site (this crate's [`cluster_bundle`]
736/// `kustomization.yaml` format-string template's per-CR source-sub-tree
737/// leaf under the top-level `spec` position, threading the same
738/// `&'static str` through a new `{path_key}` named-arg interpolation)
739/// plus one test-fixture navigation site in `mod tests` (the per-CR
740/// [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`] pin's
741/// `.get(FLUX_KUSTOMIZATION_KEY_PATH)` probe) now consult the same
742/// `&'static str`. Until this lift landed the axis carried the load-
743/// bearing `path` bytes inline at the one production emit site; a
744/// future hypothetical Flux v3 rename (`sourcePath` / `manifestsPath` /
745/// `sourceRoot`) on the production-emit site without a coordinated edit
746/// on every per-renderer consumer the absorption roadmap surfaces (the
747/// M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-
748/// Aplicacao `Kustomization` synthesis) would have silently unbound
749/// every emitted per-caixa `Kustomization` from its paired per-caixa
750/// sub-tree of the pleme-io k8s repository — the Flux v2 kustomize-
751/// controller would then either reconcile the whole GitRepository root
752/// (defaulting to `./` when the CR omits the leaf, pulling every
753/// unrelated cluster's manifests through the wrong per-caixa
754/// `Kustomization`) or refuse to reconcile at all (parking the CR at
755/// `BuildFailed` naming the missing sub-tree far from the source
756/// `caixa.lisp` / the renderer's format-string template).
757pub use caixa_core::FLUX_KUSTOMIZATION_KEY_PATH;
758
759/// Canonical substrate-side per-cluster / per-caixa
760/// `Kustomization.spec.path` source-sub-tree scalar composer — re-export
761/// of the canonical [`caixa_core::flux_kustomization_source_subtree`]
762/// so the `./clusters/<cluster>/services/<nome>` GitRepository-relative
763/// directory-tree seed every emitted per-caixa `kustomization.yaml`
764/// document mounts under its lifted [`FLUX_KUSTOMIZATION_KEY_PATH`]
765/// leaf-scalar-key lives at one composer across every caixa renderer.
766///
767/// Peer to [`FLUX_KUSTOMIZATION_KEY_PATH`] (613d7ed) — the leaf-scalar-
768/// key half of the `spec.path` `(key, value)` per-CR pair — on the
769/// paired value-half axis. Until this lift landed the two-axis
770/// composition (the `./clusters/` per-cluster prefix + the `/services/`
771/// per-caixa infix) sat as a verbatim inline
772/// `format!("./clusters/{cluster}/services/{name}")` at the sole
773/// [`cluster_bundle`] `kustomization.yaml` format-string production
774/// emit site plus a mirror-symmetric verbatim inline
775/// `format!("./clusters/{cluster}/services/{name}", …)` at its paired
776/// `cluster_bundle_kustomization_path_pins_lifted_sub_tree` test-fixture
777/// navigation site, with no compile-time link between the two sites and
778/// no compile-time link ahead of the second production-emit occurrence
779/// the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-
780/// Aplicacao `Kustomization` synthesis will surface. Both sites now
781/// consult the same canonical composer, so a future substrate-side
782/// directory-tree axis rebrand (`clusters/` → `environments/` for a
783/// multi-env-per-cluster axis extension, `services/` → `servicos/` for
784/// a portuguese-canonical directory-name migration matching the sibling
785/// `:servicos` slot spelling, a per-tenant scoping prefix for multi-
786/// tenant Aplicacao hosting) is one edit at the composer, not a
787/// coordinated sweep across every renderer's `spec.path` emit site.
788/// Same shape as the sibling [`caixa_core::oci_chart_ref`] /
789/// [`caixa_core::cilium_network_policy_name`] /
790/// [`caixa_core::gateway_api_http_route_name`] composer re-exports on
791/// the peer substrate-side canonical-load-bearing-scalar-that-consumers-
792/// key-off axis.
793pub use caixa_core::flux_kustomization_source_subtree;
794
795/// Canonical Flux v2 `Kustomization.spec.timeout` per-CR reconcile
796/// wall-clock cap leaf-scalar-key — re-export of the canonical
797/// [`caixa_core::FLUX_KUSTOMIZATION_KEY_TIMEOUT`] so the Flux v2
798/// kustomize-controller-side per-CR reconcile wall-clock cap leaf-
799/// scalar-key lives in exactly one place across every caixa
800/// renderer. Peer to the co-resident
801/// [`FLUX_KUSTOMIZATION_KEY_PATH`] (613d7ed) per-CR source-sub-tree
802/// leaf-scalar-key and [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917)
803/// per-CR garbage-collection-toggle leaf-scalar-key on the same top-
804/// level `spec` position of the emitted per-caixa `Kustomization` CR
805/// — extends the per-`Kustomization`-CR-spec leaf-scalar-key
806/// discipline from the co-resident source-sub-tree and garbage-
807/// collection-toggle axes onto the co-resident reconcile wall-clock
808/// cap axis at the mirror-symmetric top-level `spec.timeout`
809/// position. One production emit site (this crate's
810/// [`cluster_bundle`] `kustomization.yaml` format-string template's
811/// per-CR reconcile wall-clock cap leaf under the top-level `spec`
812/// position, threading the same `&'static str` through a new
813/// `{timeout_key}` named-arg interpolation) plus one test-fixture
814/// navigation site in `mod tests` (the per-CR
815/// [`cluster_bundle_kustomization_timeout_pins_lifted_default`] pin's
816/// `.get(FLUX_KUSTOMIZATION_KEY_TIMEOUT)` probe) now consult the same
817/// `&'static str`. Until this lift landed the axis carried the load-
818/// bearing `timeout` bytes inline at the one production emit site; a
819/// future hypothetical Flux v3 rename (`deadline` / `reconcileTimeout`
820/// / `maxDuration`) on the production-emit site without a coordinated
821/// edit on every per-renderer consumer the absorption roadmap
822/// surfaces (the M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR
823/// materializer's per-Aplicacao `Kustomization` synthesis) would have
824/// silently stripped the substrate's chosen reconcile-ceiling
825/// declaration from every emitted per-caixa `Kustomization` document
826/// — the Flux v2 kustomize-controller would then fall back to the
827/// upstream Flux v2 controller-side default cap, letting a
828/// persistently-failing per-caixa manifest apply consume kustomize-
829/// controller reconcile-loop cycles past the substrate's chosen
830/// ceiling with no field naming the leaf-key-drift root cause far
831/// from the source `caixa.lisp` / the renderer's format-string
832/// template. Pairs with the sibling
833/// [`DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] scalar-value half of the
834/// same `(leaf-key, scalar-value)` per-path reconcile-ceiling-
835/// declaration pair. Same shape as the sibling
836/// [`FLUX_KUSTOMIZATION_KEY_PATH`] (613d7ed) /
837/// [`FLUX_KUSTOMIZATION_KEY_PRUNE`] (8ec7917) /
838/// [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] (96581b7) /
839/// [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] (ba9ab8b) leaf-scalar-
840/// key re-exports on the peer per-Flux-v2-CR-spec-leaf-scalar-key
841/// surface.
842pub use caixa_core::FLUX_KUSTOMIZATION_KEY_TIMEOUT;
843
844/// Canonical Flux v2 `Kustomization.spec.timeout` per-CR reconcile
845/// wall-clock cap default the substrate seeds into every per-caixa
846/// `kustomization.yaml` document. Re-export of the canonical
847/// [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] so the Flux v2
848/// kustomize-controller-side per-CR reconcile-ceiling default scalar-
849/// value lives in exactly one place across every caixa renderer —
850/// [`cluster_bundle`]'s `kustomization.yaml` format-string template's
851/// sole production-code emit site (the prior inline `timeout: 5m`
852/// scalar-value literal under the top-level `spec` position, keyed by
853/// the sibling [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`] leaf-scalar-key)
854/// now consumes the same `&'static str` at emit time through one
855/// `{timeout_default}` named-arg interpolation, so a future
856/// substrate-side reconcile-ceiling migration (`"5m"` → `"3m"` on
857/// faster per-caixa idempotency-checkpoint cadence, `"5m"` → `"10m"`
858/// on larger per-caixa manifest sets — coordinated with the sibling
859/// [`DEFAULT_FLUX_RECONCILE_INTERVAL`] reconcile-poll cadence tuning
860/// cycle) is a one-line edit on the canonical
861/// [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] declaration, not
862/// a coordinated rewrite across the emit site + every future per-CR
863/// reconcile-cap consumer the substrate adds. Pairs with the sibling
864/// [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`] re-export on the same per-CR
865/// `spec.timeout` scalar-axis — the key half of the per-CR scalar-
866/// key/scalar-value pair lives at [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`],
867/// the value half's substrate-side default seed lives here. Same
868/// shape as the sibling [`DEFAULT_FLUX_RECONCILE_INTERVAL`] (908180f)
869/// / [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] (30dcdae) re-
870/// exports on the peer canonical-substrate-default-load-bearing-
871/// scalar surface.
872pub use caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT;
873
874/// Canonical FluxCD installation namespace — re-export of the lifted
875/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] so the load-bearing
876/// string lives in exactly one place across every consumer of the
877/// rendered `kustomization.yaml`'s `metadata.namespace` and
878/// `spec.sourceRef.name` axes. Both axes are the same conceptual "Flux
879/// installation namespace" the `flux bootstrap` pipeline names; until
880/// this lift landed they sat as two inline `flux-system` literals inside
881/// [`cluster_bundle`]'s `kustomization.yaml` format-string template, and
882/// any future per-edition Flux-installation-namespace rebrand on one
883/// without a coordinated edit on the other would have silently emitted a
884/// `Kustomization` outside the bootstrap controller's watch window or a
885/// dangling `sourceRef`. Same shape as the
886/// [`caixa_core::DEFAULT_NAMESPACE`] (a085b26) /
887/// [`caixa_core::DEFAULT_LIBRARY_NAME`] (41438dc) /
888/// [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`] (0a6a602) lifts on the peer
889/// canonical-load-bearing-string surface.
890pub use caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE;
891
892/// Canonical FluxCD `HelmRelease` CRD `apiVersion` — re-export of the
893/// lifted [`caixa_core::FLUX_HELMRELEASE_API_VERSION`] so the load-bearing
894/// string lives in exactly one place across the rendered Flux bundle's
895/// `helmrelease.yaml` document `apiVersion` axis + the rendered
896/// `kustomization.yaml` document's `spec.healthChecks[].apiVersion` axis.
897/// Both axes are the same conceptual "Flux v2 `HelmRelease` CRD group/
898/// version" load-bearing string and must move together on any future
899/// upstream Flux v3 migration; until this lift landed they sat as four
900/// inline `helm.toolkit.fluxcd.io/v2` literals (two render-side at lines
901/// 455, 504 + two test-fixture-side at lines 928, 970), and any future
902/// per-Flux-v3-migration version bump on one without a coordinated edit
903/// on the other would have silently routed the rendered `HelmRelease`
904/// outside the controller's `Watches` (controller-side: never reconciled,
905/// every dependent chart frozen at last-applied state) or made the
906/// `Kustomization`'s health-check dangle (apply-side: the per-resource
907/// health-gate never resolves, the parent Kustomization sits perpetually
908/// in `Reconciling`). Same shape as the
909/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lift on the
910/// sibling Flux-installation-namespace axis.
911pub use caixa_core::FLUX_HELMRELEASE_API_VERSION;
912
913/// Canonical FluxCD `GitRepository` CRD `apiVersion` — re-export of the
914/// lifted [`caixa_core::FLUX_GITREPOSITORY_API_VERSION`] so the load-bearing
915/// string lives in exactly one place across the rendered Flux bundle's
916/// `gitrepository.yaml` document `apiVersion` axis. Until this lift landed
917/// the axis sat as an inline `source.toolkit.fluxcd.io/v1` literal at line
918/// 436 of this crate's [`cluster_bundle`] format-string template, and any
919/// future per-Flux-v3-migration version bump on this axis without a
920/// coordinated edit on the sibling [`FLUX_HELMRELEASE_API_VERSION`] axis
921/// would have silently routed the rendered `GitRepository` outside the
922/// Flux v2 `source-controller`'s `Watches` (controller-side: never
923/// reconciled, the dependent HelmRelease's `chart: sourceRef` dangles,
924/// every per-Servico apply silently comes up with the prior reconciled
925/// state). Same shape as the [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
926/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts on the
927/// sibling Flux-v2-load-bearing-string axis.
928pub use caixa_core::FLUX_GITREPOSITORY_API_VERSION;
929
930/// Canonical FluxCD `Kustomization` CRD `apiVersion` — re-export of the
931/// lifted [`caixa_core::FLUX_KUSTOMIZATION_API_VERSION`] so the load-
932/// bearing string lives in exactly one place across the rendered Flux
933/// bundle's `kustomization.yaml` document `apiVersion` axis. Completes
934/// the Flux v2 controller-triplet (source-controller +
935/// helm-controller + kustomize-controller) lift alongside the sibling
936/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) and
937/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) re-exports — every
938/// per-controller CRD-group/version is now a typed substrate-side
939/// `&'static str` consumed through one `pub use caixa_core::FLUX_*`
940/// re-export.
941///
942/// Until this lift landed the axis sat as an inline
943/// `kustomize.toolkit.fluxcd.io/v1` literal in this crate's
944/// [`cluster_bundle`] `kustomization.yaml` format-string template,
945/// and any future per-Flux-v3-migration version bump on this axis
946/// without a coordinated edit on the sibling
947/// [`FLUX_HELMRELEASE_API_VERSION`] / [`FLUX_GITREPOSITORY_API_VERSION`]
948/// axes (the Flux v2 controller triplet's CRD group/versions move
949/// together upstream) would have silently routed the rendered
950/// `Kustomization` outside the Flux v2 `kustomize-controller`'s
951/// `Watches` (apply-side: the parent Kustomization is never
952/// reconciled, every dependent `HelmRelease` / `GitRepository` it
953/// keys off sits perpetually un-applied at the cluster). Same shape
954/// as the [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
955/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
956/// [`caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`] (7197d38) lifts on
957/// the sibling Flux-v2-load-bearing-string axis.
958pub use caixa_core::FLUX_KUSTOMIZATION_API_VERSION;
959
960/// Canonical FluxCD `GitRepository` CRD `kind` discriminator — re-export
961/// of the lifted [`caixa_core::FLUX_KIND_GIT_REPOSITORY`] so the load-
962/// bearing string lives in exactly one place across the three rendered
963/// Flux bundle axes that name the same K8s CRD discriminator:
964///
965/// - the rendered `gitrepository.yaml` document's top-level `kind`
966/// axis (the GitRepository CR's own discriminator);
967/// - the rendered `helmrelease.yaml` document's
968/// `spec.chart.spec.sourceRef.kind` axis (pointing back at the
969/// sibling GitRepository this chart sources from);
970/// - the rendered `kustomization.yaml` document's `spec.sourceRef.kind`
971/// axis (pointing back at the cluster's bootstrap GitRepository).
972///
973/// Until this lift landed the three axes sat as three inline
974/// `GitRepository` literals across the [`cluster_bundle`] `gitrepo` +
975/// `helmrelease` + `kustomization` format-string templates (caixa-flux
976/// /src/lib.rs:505, 556, 591). The apiserver-side CRD resolution
977/// contract is the `(apiVersion, kind)` tuple keyed against the
978/// registered `CustomResourceDefinition`; a typo at any one of the three
979/// call sites would have silently dangled the corresponding `sourceRef`
980/// at apply time (the `helm-controller` never resolves a chart for the
981/// HelmRelease, the `kustomize-controller` never reconciles the parent
982/// Kustomization, every per-Servico apply silently comes up with the
983/// prior reconciled state) with no diagnostic naming the kind-drift root
984/// cause far from the source caixa.lisp. Same shape as the
985/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
986/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
987/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) lifts on the sibling
988/// apiVersion half of the same `(apiVersion, kind)` CRD-lookup tuple —
989/// extends the discipline from the apiVersion axis of the Flux v2
990/// source-controller CRD onto its kind axis.
991pub use caixa_core::FLUX_KIND_GIT_REPOSITORY;
992
993/// Canonical FluxCD `HelmRelease` CRD `kind` discriminator — re-export
994/// of the lifted [`caixa_core::FLUX_KIND_HELM_RELEASE`] so the load-
995/// bearing string lives in exactly one place across the two rendered
996/// Flux bundle axes that name the same K8s CRD discriminator:
997///
998/// - the rendered `helmrelease.yaml` document's top-level `kind`
999/// axis (the HelmRelease CR's own discriminator);
1000/// - the rendered `kustomization.yaml` document's
1001/// `spec.healthChecks[].kind` axis (pointing back at the sibling
1002/// HelmRelease the Kustomization health-gates on before declaring
1003/// its own reconcile complete).
1004///
1005/// Until this lift landed the two axes sat as two inline `HelmRelease`
1006/// literals across the [`cluster_bundle`] `helmrelease` + `kustomization`
1007/// format-string templates (caixa-flux/src/lib.rs:580, 631). The
1008/// apiserver-side CRD resolution contract is the `(apiVersion, kind)`
1009/// tuple keyed against the registered `CustomResourceDefinition`; a
1010/// typo at either of the two call sites would have silently lost the
1011/// apply-side resolution (top-level `kind` typos surface as "no kind
1012/// 'X' is registered" at apply parse time; the nested
1013/// `healthChecks[].kind` typo silently dangles the parent
1014/// Kustomization at `Reconciling` forever) with no diagnostic naming
1015/// the kind-drift root cause far from the source caixa.lisp. Same
1016/// shape as the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
1017/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) /
1018/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
1019/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) lifts on the sibling
1020/// Flux-v2-load-bearing-string axes — extends the kind-axis discipline
1021/// from the Flux v2 source-controller CRD onto the sibling Flux v2
1022/// helm-controller CRD.
1023pub use caixa_core::FLUX_KIND_HELM_RELEASE;
1024
1025/// Canonical FluxCD `Kustomization` CRD `kind` discriminator — re-export
1026/// of the lifted [`caixa_core::FLUX_KIND_KUSTOMIZATION`] so the load-
1027/// bearing string lives in exactly one place across the rendered Flux
1028/// bundle's `Kustomization`-naming axis:
1029///
1030/// - the rendered `kustomization.yaml` document's top-level `kind`
1031/// axis (the Kustomization CR's own discriminator).
1032///
1033/// Until this lift landed the axis sat as an inline `Kustomization`
1034/// literal inside the [`cluster_bundle`] `kustomization` format-string
1035/// template (caixa-flux/src/lib.rs:651). The apiserver-side CRD
1036/// resolution contract is the `(apiVersion, kind)` tuple keyed against
1037/// the registered `CustomResourceDefinition`; a typo at this call site
1038/// would have surfaced at apply parse time as a non-self-locating "no
1039/// kind 'Kustomizaton' is registered for version
1040/// 'kustomize.toolkit.fluxcd.io/v1'" error, with the rendered parent
1041/// Kustomization never reconciling and every downstream per-Servico
1042/// `dependsOn` chain freezing at the kustomize-controller's CRD-lookup
1043/// boundary. Same shape as the [`FLUX_KIND_GIT_REPOSITORY`] (dbbcf29) /
1044/// [`FLUX_KIND_HELM_RELEASE`] (e24ea3c) /
1045/// [`FLUX_KUSTOMIZATION_API_VERSION`] (d2dd1b1) /
1046/// [`FLUX_GITREPOSITORY_API_VERSION`] (8a6c8a3) /
1047/// [`FLUX_HELMRELEASE_API_VERSION`] (55f0fd9) lifts on the sibling
1048/// Flux-v2-load-bearing-string axes — extends the kind-axis discipline
1049/// from the Flux v2 source-controller + helm-controller CRDs onto the
1050/// sibling Flux v2 kustomize-controller CRD, completing the
1051/// canonical-Flux-v2-CRD-kind-discriminator lift across the
1052/// source/helm/kustomize controller triplet.
1053pub use caixa_core::FLUX_KIND_KUSTOMIZATION;
1054
1055/// Canonical Flux v2 per-`HelmRelease` inline-chart-template container-
1056/// axis key every `caixa-flux`-emitted `HelmRelease` document nests its
1057/// per-CR chart-template block under (`spec.chart` on `HelmRelease`). Re-
1058/// export of the canonical [`caixa_core::FLUX_KEY_CHART`] so the load-
1059/// bearing Flux-v2-helm-controller-side per-`HelmRelease` chart-template
1060/// container-axis key lives in exactly one place across every caixa
1061/// renderer — the sweep converts this crate's one production-code call
1062/// site (the [`cluster_bundle`] `helmrelease.yaml` format-string
1063/// template's baked `chart:\n` container-axis key nesting the
1064/// `HelmChartTemplate` sub-document whose peer sibling lifted
1065/// [`FLUX_KEY_SOURCE_REF`] source-reference container-axis + inner
1066/// chart-name-scalar reach through) plus the two test-fixture
1067/// `.get("chart")` navigation sites in `mod tests` that probe the
1068/// emitted `spec.chart.spec.sourceRef.kind` pin onto the re-export. A
1069/// future Flux v3 rebrand of the per-`HelmRelease` chart-template
1070/// container-axis key (a hypothetical upstream fluxcd/flux2 rename from
1071/// `chart` to `Chart` / `chartTemplate` / `helmChart` / `chartRef`,
1072/// coordinated with the upstream project's per-version deprecation
1073/// cycle) now lands at one const rather than scattered across the one
1074/// emit-side format-string template + two test-fixture probe sites.
1075/// Same "the typed constant lives in one place" discipline the peer
1076/// [`FLUX_KEY_SOURCE_REF`] + [`FLUX_KEY_VALUES`] re-exports enforce on
1077/// the sibling Flux v2 per-`HelmRelease` body-key surfaces — completes
1078/// the triplet of Flux v2 per-`HelmRelease` `spec.*` body-key constants
1079/// (`spec.chart` + `spec.chart.spec.sourceRef` + `spec.values`) the
1080/// `cluster_bundle` renderer threads through its `helmrelease.yaml`
1081/// format-string template.
1082pub use caixa_core::FLUX_KEY_CHART;
1083
1084/// Canonical Flux v2 `HelmChartTemplate.spec.chart` per-CR chart-NAME-
1085/// reference leaf-scalar-axis key every `caixa-flux`-emitted
1086/// `HelmRelease` document nests inside the parent [`FLUX_KEY_CHART`]
1087/// container-axis (a nested [`KUBE_KEY_SPEC`] axis inside that
1088/// container hosts this leaf plus its sibling [`FLUX_KEY_SOURCE_REF`]
1089/// per-CR source-reference triple). Re-export of the canonical
1090/// [`caixa_core::FLUX_HELMCHART_TEMPLATE_KEY_CHART`] so the load-
1091/// bearing Flux-v2-helm-controller-side per-`HelmChartTemplate` chart-
1092/// NAME reference leaf-scalar-axis key lives in exactly one place
1093/// across every caixa renderer — the sweep converts this crate's one
1094/// production-code call site (the [`cluster_bundle`] `helmrelease.yaml`
1095/// format-string template's baked `chart: {chart_path}` leaf-scalar-
1096/// axis interpolation the peer sibling lifted [`FLUX_KEY_SOURCE_REF`]
1097/// source-reference triple's per-CR source-artifact publishes) onto
1098/// the re-export.
1099///
1100/// A future Flux v3 rebrand of the per-`HelmChartTemplate` chart-NAME
1101/// reference leaf-scalar-axis key (a hypothetical upstream fluxcd/flux2
1102/// rename from `chart` to `Chart` / `chartRef` / `chartName`,
1103/// coordinated with the upstream project's per-version deprecation
1104/// cycle) now lands at one const rather than scattered across the one
1105/// emit-side format-string template site. Same "the typed constant
1106/// lives in one place" discipline the peer [`FLUX_KEY_CHART`] +
1107/// [`FLUX_KEY_SOURCE_REF`] + [`FLUX_KEY_VALUES`] re-exports enforce
1108/// on the sibling Flux v2 per-`HelmRelease` body-key surfaces —
1109/// completes the per-`HelmRelease` chart-template `(spec.chart →
1110/// spec.chart.spec.chart + spec.chart.spec.sourceRef)` axis chain by
1111/// descending one level beneath the parent container-axis re-export
1112/// the sibling [`FLUX_KEY_CHART`] anchors.
1113///
1114/// Deliberate axis-independence discipline with the parent
1115/// [`FLUX_KEY_CHART`] container-axis re-export: both re-exports carry
1116/// the same underlying `"chart"` string today but name distinct schema
1117/// axes on the same CRD group (a container-axis parent vs a leaf-
1118/// scalar grandchild inside it), so the two `pub use` re-exports stay
1119/// sibling constants at the rustc symbol-name axis rather than
1120/// coalescing onto one canonical declaration. Peer to the deliberate
1121/// [`CILIUM_KEY_PATH`] / [`caixa_core::GATEWAY_API_KEY_PATH`] axis-
1122/// independence discipline the two-CRD-groups-sharing-a-string
1123/// sibling `"path"` re-exports established on the peer canonical-
1124/// axis-independence surface.
1125pub use caixa_core::FLUX_HELMCHART_TEMPLATE_KEY_CHART;
1126
1127/// Canonical Flux v2 per-`HelmRelease`/`Kustomization` source-reference
1128/// container-axis key every `caixa-flux`-emitted bundle document mounts
1129/// its per-CR source-of-truth `(kind, name, namespace)` reference triple
1130/// under (`spec.chart.spec.sourceRef` on `HelmRelease`, `spec.sourceRef`
1131/// on `Kustomization`). Re-export of the canonical
1132/// [`caixa_core::FLUX_KEY_SOURCE_REF`] so the load-bearing Flux-v2-source-
1133/// controller-side per-CR source-reference container-axis key lives in
1134/// exactly one place across every caixa renderer — the sweep converts
1135/// this crate's two production emit sites (the [`cluster_bundle`]
1136/// `helmrelease.yaml` format-string template's baked
1137/// `spec.chart.spec.sourceRef:\n` sub-block header + the sibling
1138/// `kustomization.yaml` format-string template's baked
1139/// `spec.sourceRef:\n` sub-block header, both now threaded through a
1140/// `{source_ref_key}` named-arg interpolation on the lifted const, closing
1141/// the last two open production sites for this axis) plus the five
1142/// test-fixture `.get("sourceRef")` navigation sites in `mod tests` (the
1143/// `helmrelease.yaml` `spec.chart.spec.sourceRef.kind` pin, the
1144/// `kustomization.yaml` `spec.sourceRef.name` + `spec.sourceRef.kind`
1145/// pins under the paired [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] +
1146/// [`FLUX_KIND_GIT_REPOSITORY`] canonical-string axes, and the two
1147/// cross-axis triplet pins that traverse both bundle documents to
1148/// pin the sibling `GitRepository`-kind axis triplet against one
1149/// canonical string) onto the re-export. A future Flux v3 rebrand of
1150/// the per-CR source-reference container-axis key (a hypothetical
1151/// upstream fluxcd/flux2 rename from `sourceRef` to `source` /
1152/// `sourceReference` / `sourceOf`, coordinated with the upstream
1153/// project's per-version deprecation cycle) now lands at one const
1154/// rather than scattered across the two per-CR format-string templates
1155/// + five test-fixture probe sites. Same "the typed constant lives in
1156/// one place" discipline the peer [`FLUX_KIND_GIT_REPOSITORY`] /
1157/// [`FLUX_KIND_HELM_RELEASE`] / [`FLUX_KIND_KUSTOMIZATION`] +
1158/// [`FLUX_HELMRELEASE_API_VERSION`] / [`FLUX_GITREPOSITORY_API_VERSION`]
1159/// / [`FLUX_KUSTOMIZATION_API_VERSION`] re-exports enforce on the
1160/// sibling canonical-Flux-v2-load-bearing-string surfaces.
1161pub use caixa_core::FLUX_KEY_SOURCE_REF;
1162
1163/// Canonical Flux v2 per-`HelmRelease` values-override block-body-axis
1164/// key every `caixa-flux`-emitted `HelmRelease` document nests its per-
1165/// cluster value overrides under (`spec.values` on `HelmRelease`). Re-
1166/// export of the canonical [`caixa_core::FLUX_KEY_VALUES`] so the load-
1167/// bearing Flux-v2-helm-controller-side per-`HelmRelease` values-
1168/// override block-body-axis key lives in exactly one place across every
1169/// caixa renderer — the sweep converts this crate's one production-code
1170/// call site (the [`cluster_bundle`] `helmrelease.yaml` format-string
1171/// template's baked `values:\n` key beside the sibling lifted
1172/// [`DEFAULT_LIBRARY_NAME`] wrap key + [`HELM_VALUES_KEY_ENABLED`]
1173/// enable-toggle) plus the [`upsert_into_helmrelease_programs`]
1174/// upsert-path's `spec.values.programs[]` write-side navigation onto the
1175/// re-export, and threads three test-fixture `.get("values")` block-
1176/// body-axis probe sites in `mod tests` through the same const. A
1177/// future Flux v3 rebrand of the per-`HelmRelease` values-override
1178/// block-body-axis key (a hypothetical upstream fluxcd/flux2 rename
1179/// from `values` to `Values` / `chartValues` / `overrides`, coordinated
1180/// with the upstream project's per-version deprecation cycle) now lands
1181/// at one const rather than scattered across the one emit-side format-
1182/// string template + one upsert-side write-side navigation + three
1183/// test-fixture probe sites. Same "the typed constant lives in one
1184/// place" discipline the peer [`FLUX_KEY_SOURCE_REF`] +
1185/// [`FLUX_KIND_GIT_REPOSITORY`] / [`FLUX_KIND_HELM_RELEASE`] /
1186/// [`FLUX_KIND_KUSTOMIZATION`] + [`FLUX_HELMRELEASE_API_VERSION`] /
1187/// [`FLUX_GITREPOSITORY_API_VERSION`] / [`FLUX_KUSTOMIZATION_API_VERSION`]
1188/// re-exports enforce on the sibling canonical-Flux-v2-load-bearing-
1189/// string surfaces.
1190pub use caixa_core::FLUX_KEY_VALUES;
1191
1192/// Canonical Flux v2 per-`Kustomization` health-gate reference-list
1193/// container-axis key every `caixa-flux`-emitted `kustomization.yaml`
1194/// document mounts its per-sibling-`HelmRelease` health-probe list under
1195/// (`spec.healthChecks` on `Kustomization`). Re-export of the canonical
1196/// [`caixa_core::FLUX_KEY_HEALTH_CHECKS`] so the load-bearing Flux-v2-
1197/// kustomize-controller-side per-`Kustomization` health-gate reference-
1198/// list container-axis key lives in exactly one place across every caixa
1199/// renderer — the sweep converts this crate's one production-code call
1200/// site (the [`cluster_bundle`] `kustomization.yaml` format-string
1201/// template's baked `healthChecks:\n` container-axis key nesting the
1202/// per-entry `[]NamespacedObjectKindReference` list whose peer sibling
1203/// lifted [`FLUX_HELMRELEASE_API_VERSION`] per-entry `apiVersion` axis +
1204/// [`FLUX_KIND_HELM_RELEASE`] per-entry `kind` axis the health-gate
1205/// references) plus the three test-fixture `.get("healthChecks")`
1206/// navigation sites in `mod tests` that probe the emitted per-entry
1207/// `apiVersion` + `kind` pin onto the re-export. A future Flux v3 rebrand
1208/// of the per-`Kustomization` health-gate reference-list container-axis
1209/// key (a hypothetical upstream fluxcd/flux2 rename from `healthChecks`
1210/// to `HealthChecks` / `healthchecks` / `healthcheck` / `health_checks`
1211/// / `probes`, coordinated with the upstream project's per-version
1212/// deprecation cycle) now lands at one const rather than scattered across
1213/// the one emit-side format-string template + three test-fixture probe
1214/// sites. Same "the typed constant lives in one place" discipline the
1215/// peer [`FLUX_KEY_SOURCE_REF`] + [`FLUX_KEY_CHART`] + [`FLUX_KEY_VALUES`]
1216/// re-exports enforce on the sibling Flux v2 per-`HelmRelease` +
1217/// per-`Kustomization` body-key surfaces — completes the quartet of Flux
1218/// v2 `spec.*` body-key constants (`spec.chart` + `spec.chart.spec.sourceRef`
1219/// + `spec.values` + `spec.healthChecks`) the `cluster_bundle` renderer
1220/// threads through its two format-string templates.
1221pub use caixa_core::FLUX_KEY_HEALTH_CHECKS;
1222
1223/// Canonical Flux v2 per-CR reconcile-poll cadence scalar-axis key every
1224/// `caixa-flux`-emitted Flux document (`GitRepository`, `HelmRelease`,
1225/// `Kustomization`) declares its per-CR `spec.interval` reconcile cadence
1226/// under. Re-export of the canonical [`caixa_core::FLUX_KEY_INTERVAL`] so
1227/// the load-bearing Flux-v2-controller-triplet-side per-CR reconcile-poll
1228/// cadence scalar-axis key lives in exactly one place across every caixa
1229/// renderer — the sweep converts this crate's three production-code call
1230/// sites (the [`cluster_bundle`] `gitrepository.yaml` + `helmrelease.yaml`
1231/// + `kustomization.yaml` format-string templates' baked `interval:`
1232/// scalar-axis keys, one per Flux v2 CRD kind, nested alongside the peer
1233/// sibling lifted per-CR `apiVersion` + `kind` axis re-exports on this
1234/// crate — [`FLUX_GITREPOSITORY_API_VERSION`] + [`FLUX_KIND_GIT_REPOSITORY`]
1235/// on the source-controller CRD, [`FLUX_HELMRELEASE_API_VERSION`] +
1236/// [`FLUX_KIND_HELM_RELEASE`] on the helm-controller CRD, and
1237/// [`FLUX_KUSTOMIZATION_API_VERSION`] + [`FLUX_KIND_KUSTOMIZATION`] on the
1238/// kustomize-controller CRD) onto the re-export. A future Flux v3 rebrand
1239/// of the per-CR reconcile-poll cadence scalar-axis key (a hypothetical
1240/// upstream fluxcd/flux2 rename from `interval` to `Interval` / `period`
1241/// / `cadence` / `pollInterval` / `reconcileInterval`, coordinated with
1242/// the upstream project's per-version deprecation cycle) now lands at one
1243/// const rather than scattered across three per-CR emit-side format-string
1244/// template sites. Same "the typed constant lives in one place" discipline
1245/// the peer [`FLUX_KEY_SOURCE_REF`] + [`FLUX_KEY_CHART`] + [`FLUX_KEY_VALUES`]
1246/// + [`FLUX_KEY_HEALTH_CHECKS`] re-exports enforce on the sibling Flux v2
1247/// per-CR body-key surfaces — extends the per-CR body-key lift trajectory
1248/// onto the sibling *cross-CR-shared* reconcile-poll cadence scalar-axis
1249/// every Flux v2 controller reads to bind its per-CR poll cycle.
1250pub use caixa_core::FLUX_KEY_INTERVAL;
1251
1252/// Canonical Flux v2 per-`GitRepository` `spec.ref.tag` git-tag-
1253/// selector scalar-axis key every [`cluster_bundle`]-rendered
1254/// `gitrepository.yaml` document declares on the tag-arm of the
1255/// [`GitRefSpec`] discriminated-union. Re-export of the canonical
1256/// [`caixa_core::FLUX_GITREPOSITORY_REF_KEY_TAG`] so the sub-selector
1257/// byte-string lives in exactly one place: the two consumer sites
1258/// (the YAML emit-side `gitref_field` composer and the human-readable
1259/// `tag_human` narrator prose) both now read through the lifted
1260/// [`GitRefSpec::ref_field_name`] dispatch that maps the tag-arm of
1261/// the discriminated-union onto this canonical scalar. Pairs with
1262/// [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] +
1263/// [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] on the sibling per-shape arms
1264/// of the same FluxCD source-controller `GitRepository.spec.ref`
1265/// discriminated-union axis — three consts, one per arm, one canonical
1266/// dispatch. See the caixa-core docstring for the full lift rationale.
1267pub use caixa_core::FLUX_GITREPOSITORY_REF_KEY_TAG;
1268
1269/// Canonical Flux v2 per-`GitRepository` `spec.ref.branch` git-branch-
1270/// selector scalar-axis key — peer of [`FLUX_GITREPOSITORY_REF_KEY_TAG`]
1271/// on the branch-arm of the [`GitRefSpec`] discriminated-union.
1272/// Re-export of [`caixa_core::FLUX_GITREPOSITORY_REF_KEY_BRANCH`]; see
1273/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] for the full lift rationale.
1274pub use caixa_core::FLUX_GITREPOSITORY_REF_KEY_BRANCH;
1275
1276/// Canonical Flux v2 per-`GitRepository` `spec.ref.commit` git-commit-
1277/// selector scalar-axis key — peer of [`FLUX_GITREPOSITORY_REF_KEY_TAG`]
1278/// on the commit-arm of the [`GitRefSpec`] discriminated-union.
1279/// Re-export of [`caixa_core::FLUX_GITREPOSITORY_REF_KEY_COMMIT`]; see
1280/// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] for the full lift rationale.
1281pub use caixa_core::FLUX_GITREPOSITORY_REF_KEY_COMMIT;
1282
1283/// Canonical Flux v2 per-`GitRepository` `spec.ref` ref-selection
1284/// discriminated-union parent container-axis key every
1285/// [`cluster_bundle`]-rendered `gitrepository.yaml` document mounts
1286/// its per-shape `{tag, branch, commit}` sub-selector arm under.
1287/// Re-export of the canonical
1288/// [`caixa_core::FLUX_GITREPOSITORY_KEY_REF`] so the container-axis
1289/// byte-string lives in exactly one place across every consumer:
1290/// the writer-side `cluster_bundle` `gitrepo` template composer's
1291/// `ref:` sub-block header (the sole production emission site the
1292/// prior inline `"ref:"` literal sat at) + the peer test-fixture
1293/// `.get("ref")` sub-selector traversal (the sole test-side reader
1294/// site the prior inline `"ref"` literal sat at) both now navigate
1295/// through the same `&'static str`. Nests one level above the
1296/// sibling [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
1297/// [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] /
1298/// [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] per-shape arm sub-selector
1299/// triple it wraps — the parent container-axis KEY now moves
1300/// through one lifted const alongside its already-lifted per-shape
1301/// arm sub-selector-KEY triple, so a future Flux v3 sub-schema
1302/// rebrand (an upstream `fluxcd/flux2` rename of the ref-selection
1303/// container-axis from `spec.ref` to `spec.gitRef` /
1304/// `spec.source.ref`) lands as one const edit coordinated with the
1305/// sibling per-shape arm lifts. See the caixa-core docstring for the
1306/// full lift rationale.
1307pub use caixa_core::FLUX_GITREPOSITORY_KEY_REF;
1308
1309/// Canonical Flux v2 per-`GitRepository` `spec.url` remote-repo-URL
1310/// leaf-scalar-axis key every [`cluster_bundle`]-rendered
1311/// `gitrepository.yaml` document declares. Re-export of the canonical
1312/// [`caixa_core::FLUX_GITREPOSITORY_KEY_URL`] so the byte-string lives
1313/// in exactly one place: the writer-side `cluster_bundle` `gitrepo`
1314/// template composer's `url:` sub-key (the sole production emission
1315/// site the prior inline `"url:"` literal sat at). Sibling to the
1316/// already-lifted [`FLUX_GITREPOSITORY_KEY_REF`] on the peer per-CR
1317/// `spec.ref` container-axis surface — these two constants together
1318/// with the reconcile-cadence [`FLUX_KEY_INTERVAL`] enumerate the
1319/// canonical `GitRepository.spec.*` per-CR sub-block key surface
1320/// caixa-flux emits today. See the caixa-core docstring for the full
1321/// lift rationale.
1322pub use caixa_core::FLUX_GITREPOSITORY_KEY_URL;
1323
1324/// Canonical Flux v2 per-cluster-bundle `HelmRelease` document filename
1325/// every [`cluster_bundle`]-rendered `BundleFile` carries at its per-file
1326/// `path` axis — re-export of the lifted
1327/// [`caixa_core::FLUX_HELMRELEASE_YAML_FILENAME`] so the fixed filename
1328/// the cluster-side FluxCD `kustomize-controller` looks up when it opens
1329/// the per-Servico bundle directory lives in exactly one place across
1330/// every caixa renderer. The single source of truth all thirteen
1331/// consumers reach for — one production [`cluster_bundle`] `BundleFile`
1332/// assembly's `HelmRelease` document `path` axis plus a dozen test-side
1333/// round-trip navigators that reach into the rendered bundle by the
1334/// same filename to pin per-CR body-axis emission — now consult the
1335/// same `&'static str`. Pin the equality + `&'static` static-data
1336/// identity so any local re-introduction of a sibling `pub const
1337/// FLUX_HELMRELEASE_YAML_FILENAME: &str = "…"` at this crate is a
1338/// build-time test failure naming the offending drift, not a silent
1339/// FluxCD `kustomize-controller` "no `HelmRelease` document found under
1340/// this bundle" reroute at cluster-side reconcile time far from the
1341/// drift site. Peer to the [`HELM_CHART_YAML_FILENAME`]
1342/// (`caixa_core::HELM_CHART_YAML_FILENAME`, c2c99b0) /
1343/// [`HELM_VALUES_YAML_FILENAME`] (`caixa_core::HELM_VALUES_YAML_FILENAME`,
1344/// 9a980ba) re-exports on the sibling Helm-chart-directory filename
1345/// surfaces — pivots the canonical-filename single-sourcing discipline
1346/// from the per-Helm-chart-directory metadata / values file axes onto
1347/// the sibling per-Flux-v2-bundle `HelmRelease` document filename axis
1348/// this crate's [`cluster_bundle`] renders.
1349pub use caixa_core::FLUX_HELMRELEASE_YAML_FILENAME;
1350
1351/// Canonical Flux v2 per-cluster-bundle `GitRepository` document
1352/// filename every [`cluster_bundle`]-rendered `BundleFile` carries at
1353/// its per-file `path` axis — re-export of the lifted
1354/// [`caixa_core::FLUX_GITREPOSITORY_YAML_FILENAME`] so the fixed
1355/// filename the cluster-side FluxCD `source-controller` looks up when
1356/// it opens the per-Servico bundle directory lives in exactly one
1357/// place across every caixa renderer. Pairs with the sibling
1358/// [`FLUX_HELMRELEASE_YAML_FILENAME`] +
1359/// [`FLUX_KUSTOMIZATION_YAML_FILENAME`] re-exports to close the
1360/// per-bundle `(gitrepository, helmrelease, kustomization)` filename
1361/// axis triple every rendered cluster bundle carries — the single
1362/// source of truth all nine consumers reach for (one production
1363/// [`cluster_bundle`] `BundleFile` assembly's `GitRepository`
1364/// document `path` axis plus eight test-side round-trip navigators
1365/// that reach into the rendered bundle by the same filename to pin
1366/// per-CR body-axis emission) now consult the same `&'static str`.
1367/// Pin the equality + `&'static` static-data identity so any local
1368/// re-introduction of a sibling `pub const
1369/// FLUX_GITREPOSITORY_YAML_FILENAME: &str = "…"` at this crate is a
1370/// build-time test failure naming the offending drift, not a silent
1371/// FluxCD `source-controller` "no `GitRepository` document found
1372/// under this bundle" reroute at cluster-side reconcile time far
1373/// from the drift site. Peer to the sibling
1374/// [`FLUX_HELMRELEASE_YAML_FILENAME`] (ba7b0b2) re-export — extends
1375/// the canonical-Flux-v2-bundle-filename lifted-const discipline from
1376/// the middle coordinate of the filename triple onto its first
1377/// coordinate.
1378pub use caixa_core::FLUX_GITREPOSITORY_YAML_FILENAME;
1379
1380/// Canonical Flux v2 per-cluster-bundle `Kustomization` document
1381/// filename every [`cluster_bundle`]-rendered `BundleFile` carries at
1382/// its per-file `path` axis — re-export of the lifted
1383/// [`caixa_core::FLUX_KUSTOMIZATION_YAML_FILENAME`] so the fixed
1384/// filename the cluster-side FluxCD `kustomize-controller` looks up
1385/// when it opens the per-Servico bundle directory lives in exactly
1386/// one place across every caixa renderer. Pairs with the sibling
1387/// [`FLUX_GITREPOSITORY_YAML_FILENAME`] +
1388/// [`FLUX_HELMRELEASE_YAML_FILENAME`] re-exports to close the
1389/// per-bundle `(gitrepository, helmrelease, kustomization)` filename
1390/// axis triple every rendered cluster bundle carries — the single
1391/// source of truth all sixteen consumers reach for (one production
1392/// [`cluster_bundle`] `BundleFile` assembly's `Kustomization`
1393/// document `path` axis plus fifteen test-side round-trip navigators
1394/// that reach into the rendered bundle by the same filename to pin
1395/// per-CR body-axis emission) now consult the same `&'static str`.
1396/// Pin the equality + `&'static` static-data identity so any local
1397/// re-introduction of a sibling `pub const
1398/// FLUX_KUSTOMIZATION_YAML_FILENAME: &str = "…"` at this crate is a
1399/// build-time test failure naming the offending drift, not a silent
1400/// FluxCD `kustomize-controller` "no `Kustomization` document found
1401/// under this bundle" reroute at cluster-side reconcile time far
1402/// from the drift site. Peer to the sibling
1403/// [`FLUX_HELMRELEASE_YAML_FILENAME`] (ba7b0b2) +
1404/// [`FLUX_GITREPOSITORY_YAML_FILENAME`] (this commit) re-exports —
1405/// closes the canonical-Flux-v2-bundle-filename lifted-const
1406/// discipline on the third coordinate of the filename triple.
1407pub use caixa_core::FLUX_KUSTOMIZATION_YAML_FILENAME;
1408
1409/// Canonical Helm library-chart name every `lareira-<nome>` chart
1410/// depends on — re-export of the lifted [`caixa_core::DEFAULT_LIBRARY_NAME`]
1411/// so the load-bearing string lives in exactly one place across every
1412/// caixa renderer. The wrap key the `cluster_bundle` `helmrelease.yaml`
1413/// template uses under `spec.values.<library>:` to thread the per-cluster
1414/// overrides through to the rendered chart's dep block must match the
1415/// peer `caixa-helm` chart's `dependencies[0].name` axis exactly
1416/// (Helm's per-dep alias convention scopes values under the dep's
1417/// `name:` when no `alias:` is set), and both axes now consult the same
1418/// `&'static str`. Same shape as the [`caixa_core::DEFAULT_NAMESPACE`]
1419/// (a085b26) / [`caixa_core::DEFAULT_SERVICO_PORT`] (1e22add) lifts on
1420/// the peer canonical-K8s-axis-constant surface.
1421pub use caixa_core::DEFAULT_LIBRARY_NAME;
1422
1423/// Canonical `pleme-computeunit` library-chart values-block enable-toggle
1424/// key — re-export of the lifted [`caixa_core::HELM_VALUES_KEY_ENABLED`]
1425/// so the values-block enable-toggle every rendered `HelmRelease` /
1426/// upstream `values.yaml` carries under its [`DEFAULT_LIBRARY_NAME`] wrap
1427/// key lives in exactly one place across every caixa renderer. The single
1428/// production-code call site consuming it is [`cluster_bundle`]'s
1429/// `helmrelease.yaml` format-string template (formerly an inline
1430/// `enabled: true\n` literal at `caixa-flux/src/lib.rs:844`); the peer
1431/// test-side round-trip navigator
1432/// (`cluster_bundle_helmrelease_wraps_library_values_under_lifted_default_library_name`)
1433/// also consults the re-export so a rebrand of the library-chart's per-
1434/// values enable-toggle axis lands at one const and reaches every
1435/// consumer by construction. A drifted local
1436/// `pub const HELM_VALUES_KEY_ENABLED: &str = "…"` (or any sibling per-
1437/// renderer variant that inlined a stale `"enabled"` / `"enable"` /
1438/// `"disabled"` literal) would silently emit a `HelmRelease` whose per-
1439/// cluster override lands under one key while
1440/// [`caixa_helm::build_values_yaml`]'s default-off toggle inside the
1441/// rendered `values.yaml` lands under another — Helm's per-values merge
1442/// treats them as sibling scalars, the enable-toggle the library chart's
1443/// own template consults never sees the flip, and the workload silently
1444/// comes up with the library chart's admission-time defaults instead of
1445/// the per-cluster override the operator set. Same shape as the
1446/// [`DEFAULT_LIBRARY_NAME`] / [`KUBE_KEY_SPEC`] / [`FLUX_HELMRELEASE_API_VERSION`]
1447/// re-exports on the sibling canonical-Helm-load-bearing-string /
1448/// canonical-K8s-CR-body-key / canonical-Flux-CRD-apiVersion axes.
1449pub use caixa_core::HELM_VALUES_KEY_ENABLED;
1450
1451/// Canonical K8s CR top-level `spec` key. Re-export of the canonical
1452/// [`caixa_core::KUBE_KEY_SPEC`] so the per-kind body key lives in
1453/// exactly one place across every caixa renderer — caixa-flux's
1454/// `programs_yaml_entry` (the upstream ComputeUnit YAML's
1455/// `spec.*` axis the rendered programs.yaml entry splices from),
1456/// `upsert_into_helmrelease_programs` (the canonical
1457/// `spec.values.programs[]` path the `lareira-fleet-programs`
1458/// HelmRelease keys the per-Servico entry list under), and each of the
1459/// three [`cluster_bundle`] format-string templates' four `spec:`
1460/// YAML label positions (`gitrepository.yaml` top-level +
1461/// `helmrelease.yaml` top-level + `helmrelease.yaml` `spec.chart.spec`
1462/// nested + `kustomization.yaml` top-level) all consult the same
1463/// `&'static str` as the peer caixa-mesh / caixa-helm renderers'
1464/// `KUBE_KEY_SPEC` re-exports. The prior inline `"spec"` literals at
1465/// the production-code call sites would have let a typo on one site
1466/// (e.g. `"Spec"`, `"specs"`, `"spec_"`) silently emit a
1467/// programs.yaml entry that no `lareira-fleet-programs` schema
1468/// validator recognizes; the `Error::MissingField("spec")` paths now
1469/// thread the same `&'static str` through the diagnostic surface so
1470/// the error message stays byte-identical to the key it failed to
1471/// find. Same shape as the [`FLUX_HELMRELEASE_API_VERSION`] /
1472/// [`DEFAULT_LIBRARY_NAME`] re-exports on the sibling
1473/// canonical-Flux-load-bearing-string axes. Peer with the sibling
1474/// [`KUBE_KEY_METADATA`] / [`KUBE_KEY_KIND`] /
1475/// [`KUBE_KEY_API_VERSION`] re-exports on the other three canonical
1476/// K8s-CR top-level block-scope label axes the `cluster_bundle`
1477/// format-string templates thread through named-arg interpolation.
1478pub use caixa_core::KUBE_KEY_SPEC;
1479
1480/// Canonical K8s CR top-level `metadata` key. Re-export of the canonical
1481/// [`caixa_core::KUBE_KEY_METADATA`] so the per-kind metadata block key
1482/// lives in exactly one place across every caixa renderer — caixa-flux's
1483/// `programs_yaml_entry` (the upstream ComputeUnit YAML's `metadata.namespace`
1484/// axis the rendered programs.yaml entry's `namespace` field reads from)
1485/// now consults the same `&'static str` as the peer caixa-mesh renderer's
1486/// `KUBE_KEY_METADATA` re-export. The prior inline `"metadata"` literals
1487/// at the production-code + drift-detection call sites would have let a
1488/// typo on one site (e.g. `"Metadata"`, `"meta-data"`, `"medadata"`)
1489/// silently miss the ComputeUnit's `metadata.namespace` lookup and fall
1490/// back to `DEFAULT_NAMESPACE` even when the ComputeUnit YAML pinned a
1491/// distinct target namespace; the lift routes every K8s-CR-top-level-
1492/// metadata-axis retrieval through the same `&'static str` so drift
1493/// between any two sites becomes a single-edit fix at the caixa-core
1494/// const definition. Same shape as the [`KUBE_KEY_SPEC`] re-export on
1495/// the sibling K8s-CR top-level-spec-axis.
1496pub use caixa_core::KUBE_KEY_METADATA;
1497
1498/// Canonical K8s CR top-level `kind` key. Re-export of the canonical
1499/// [`caixa_core::KUBE_KEY_KIND`] so the per-CR-kind-axis discriminator
1500/// key lives in exactly one place across every caixa renderer —
1501/// caixa-flux's `cluster_bundle` drift-detection pins that traverse the
1502/// rendered `gitrepository.yaml` / `helmrelease.yaml` / `kustomization.yaml`
1503/// documents to assert the top-level `kind` + nested `sourceRef.kind`
1504/// / `healthChecks[].kind` axes bind to the lifted
1505/// [`FLUX_KIND_GIT_REPOSITORY`] / [`FLUX_KIND_HELM_RELEASE`] /
1506/// [`FLUX_KIND_KUSTOMIZATION`] discriminators now consult the same
1507/// `&'static str` as the peer caixa-mesh renderer's `KUBE_KEY_KIND`
1508/// re-export (615a13d). The prior inline `"kind"` literals at every
1509/// drift-detection cross-axis-pin call site in this crate would have let
1510/// a typo on any one site (e.g. `"Kind"`, `"kinds"`, `"knid"`) silently
1511/// miss the per-CR kind-axis retrieval — the equality assertion would
1512/// then compare `None` against `Some("GitRepository")` /
1513/// `Some("HelmRelease")` / `Some("Kustomization")` rather than the
1514/// expected discriminator, masking the sibling `FLUX_KIND_*` re-export
1515/// drift the pin was meant to catch under a `.expect("… present")` panic
1516/// on the missing `.and_then` chain. The lift routes every K8s-CR-
1517/// top-level-kind-axis retrieval through the same `&'static str` so
1518/// drift between any two sites becomes a single-edit fix at the
1519/// caixa-core const definition. Same shape as the [`KUBE_KEY_SPEC`] +
1520/// [`KUBE_KEY_METADATA`] re-exports on the sibling K8s-CR top-level-spec
1521/// / top-level-metadata axes — completes the per-K8s-CR top-level
1522/// `(spec, metadata, kind)` axis re-export triple every rendered Flux
1523/// bundle document navigates.
1524pub use caixa_core::KUBE_KEY_KIND;
1525
1526/// Canonical K8s CR top-level `apiVersion` key. Re-export of the
1527/// canonical [`caixa_core::KUBE_KEY_API_VERSION`] so the per-CR-
1528/// group/version-axis discriminator key lives in exactly one place
1529/// across every caixa renderer — caixa-flux's [`cluster_bundle`]
1530/// drift-detection pins that traverse the rendered
1531/// `gitrepository.yaml` / `helmrelease.yaml` / `kustomization.yaml`
1532/// documents to assert the top-level `apiVersion` axis + the
1533/// `kustomization.yaml`'s nested `spec.healthChecks[].apiVersion`
1534/// axis bind to the lifted [`FLUX_GITREPOSITORY_API_VERSION`] /
1535/// [`FLUX_HELMRELEASE_API_VERSION`] / [`FLUX_KUSTOMIZATION_API_VERSION`]
1536/// controller-triplet CRD-group/versions now consult the same
1537/// `&'static str` as the sibling [`KUBE_KEY_SPEC`] / [`KUBE_KEY_METADATA`]
1538/// / [`KUBE_KEY_KIND`] re-exports on the peer K8s-CR top-level axes.
1539/// The prior inline `"apiVersion"` literals at every drift-detection
1540/// cross-axis-pin call site in this crate would have let a typo on
1541/// any one site (e.g. `"ApiVersion"`, `"api_version"`, `"apiversion"`,
1542/// `"apiVer"`) silently miss the per-CR apiVersion-axis retrieval —
1543/// the equality assertion would then compare `None` against
1544/// `Some("source.toolkit.fluxcd.io/v1")` /
1545/// `Some("helm.toolkit.fluxcd.io/v2")` /
1546/// `Some("kustomize.toolkit.fluxcd.io/v1")` rather than the expected
1547/// controller-triplet CRD-group/version, masking the sibling
1548/// `FLUX_*_API_VERSION` re-export drift the pin was meant to catch
1549/// under a `.expect("… present")` panic on the missing `.and_then`
1550/// chain. The lift routes every K8s-CR top-level-apiVersion-axis
1551/// retrieval through the same `&'static str` so drift between any
1552/// two sites becomes a single-edit fix at the caixa-core const
1553/// definition, extending the discipline the sibling [`KUBE_KEY_SPEC`]
1554/// / [`KUBE_KEY_METADATA`] / [`KUBE_KEY_KIND`] re-exports establish
1555/// onto the last of the four K8s-CR top-level axes (`apiVersion`,
1556/// `kind`, `metadata`, `spec`) every rendered Flux v2 bundle
1557/// document declares — completes the per-K8s-CR top-level
1558/// `(apiVersion, kind, metadata, spec)` axis re-export quartet
1559/// across this crate.
1560pub use caixa_core::KUBE_KEY_API_VERSION;
1561
1562/// Canonical K8s CR `metadata.namespace` key. Re-export of the canonical
1563/// [`caixa_core::KUBE_KEY_NAMESPACE`] so the per-CR namespace-axis key
1564/// lives in exactly one place across every caixa renderer — caixa-flux's
1565/// [`programs_yaml_entry`] threads the ComputeUnit YAML's
1566/// `metadata.namespace` retrieval and the emitted `programs:[]` entry's
1567/// isomorphic `namespace:` field (the `lareira-fleet-programs` chart's
1568/// per-Servico namespace axis, populated verbatim from the ComputeUnit's
1569/// `metadata.namespace` per the docstring on `programs_yaml_entry` above)
1570/// through this key, [`cluster_bundle`]'s rendered `kustomization.yaml`
1571/// drift-detection pin traverses the emitted document's
1572/// `metadata.namespace` axis to assert it binds to the lifted
1573/// [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] (the bootstrap kustomize-
1574/// controller's watch window) through this same key, and each of the
1575/// three [`cluster_bundle`] format-string templates' five `namespace:`
1576/// YAML label positions — `gitrepository.yaml` top-level
1577/// `metadata.namespace`, `helmrelease.yaml` top-level
1578/// `metadata.namespace` + nested `spec.chart.spec.sourceRef.namespace`,
1579/// `kustomization.yaml` top-level `metadata.namespace` + nested
1580/// `spec.healthChecks[].namespace` — thread this `&'static str`
1581/// through named-arg interpolation instead of the prior five inline
1582/// `namespace:` label literals.
1583///
1584/// The prior inline `"namespace"` literals at the production-code
1585/// (`programs_yaml_entry` read + write) and drift-detection call sites
1586/// would have let a typo on any one site (e.g. `"Namespace"`,
1587/// `"name space"`, `"namesapce"`, the canonical transposition) silently
1588/// miss the ComputeUnit's `metadata.namespace` lookup and fall back to
1589/// [`DEFAULT_NAMESPACE`] even when the ComputeUnit YAML pinned a
1590/// distinct target namespace, or write a `namesapce:` key that no
1591/// `lareira-fleet-programs` schema validator recognizes, or mask a
1592/// drifted [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] regression by returning
1593/// `None` from the `.get("namesapce")` retrieval so the equality
1594/// assertion never sees the true axis value under the `.expect(…)`
1595/// panic on the missing `.and_then` chain. The lift routes every
1596/// K8s-CR-`metadata.namespace`-axis retrieval / emission through the
1597/// same `&'static str` so drift between any two sites becomes a
1598/// single-edit fix at the caixa-core const definition. Same shape as
1599/// the [`KUBE_KEY_METADATA`] / [`KUBE_KEY_SPEC`] / [`KUBE_KEY_KIND`] /
1600/// [`KUBE_KEY_API_VERSION`] re-exports on the sibling K8s-CR top-level
1601/// axes — extends the discipline the top-level `(apiVersion, kind,
1602/// metadata, spec)` axis re-export quartet establishes onto the
1603/// canonical `metadata.namespace` nested axis every rendered Flux v2
1604/// bundle document navigates.
1605pub use caixa_core::KUBE_KEY_NAMESPACE;
1606
1607/// Canonical K8s CR `metadata.name` key. Re-export of the canonical
1608/// [`caixa_core::KUBE_KEY_NAME`] so the per-CR name-axis key lives in
1609/// exactly one place across every caixa renderer. Each of the three
1610/// [`cluster_bundle`] format-string templates' six `name:` YAML label
1611/// positions — `gitrepository.yaml` top-level `metadata.name`,
1612/// `helmrelease.yaml` top-level `metadata.name` + nested
1613/// `spec.chart.spec.sourceRef.name`, `kustomization.yaml` top-level
1614/// `metadata.name` + nested `spec.sourceRef.name` + nested
1615/// `spec.healthChecks[].name` — thread this `&'static str` through
1616/// named-arg interpolation instead of the prior six inline `name:`
1617/// label literals.
1618///
1619/// The prior inline `"name"` literals at the production-side call
1620/// sites would have let a typo on any one site (e.g. `"Name"`,
1621/// `"nane"`, `"nam"`, the canonical transposition) silently emit a
1622/// document whose per-CR `metadata.name` axis the apiserver-side
1623/// ObjectMeta parser cannot key on — the `helm-controller` /
1624/// `source-controller` / `kustomize-controller` would then treat the
1625/// rendered document as an anonymous CR (or the apiserver would
1626/// reject the apply with a schema-validation error naming the wrong
1627/// key), with no field naming the label-drift root cause far from
1628/// the source caixa.lisp. Now the emit-side and retrieval-side both
1629/// consult one substrate-owned `&'static str`, and the raw-byte-
1630/// label pin structurally forbids the emit format-string from
1631/// drifting away from the canonical key without failing at test
1632/// time. Same shape as the [`KUBE_KEY_NAMESPACE`] /
1633/// [`KUBE_KEY_METADATA`] / [`KUBE_KEY_SPEC`] / [`KUBE_KEY_KIND`] /
1634/// [`KUBE_KEY_API_VERSION`] re-exports on the sibling K8s-CR
1635/// canonical-key axes — extends the discipline the top-level
1636/// `(apiVersion, kind, metadata, spec)` axis re-export quartet +
1637/// the sibling `metadata.namespace` nested-axis re-export establish
1638/// onto the paired `metadata.name` nested axis every rendered Flux
1639/// v2 bundle document navigates as the other half of the `(name,
1640/// namespace)` ObjectMeta / sourceRef / healthCheck identity-pair.
1641pub use caixa_core::KUBE_KEY_NAME;
1642
1643/// Local re-export of [`caixa_core::FLEET_PROGRAMS_KEY_PROGRAMS`] —
1644/// the canonical `lareira-fleet-programs` values-schema array key
1645/// (`programs:` — the exact YAML key the fleet-programs library chart
1646/// reads under `.Values.programs[]` to iterate one `ComputeUnit` CR per
1647/// entry). This crate's two writer-side upsert paths
1648/// ([`upsert_into_helmrelease_programs`] on the aggregator-HelmRelease
1649/// shape, [`upsert_into_programs_yaml`] on the bare-values.yaml shape)
1650/// both anchor on this key when walking the entry sequence to
1651/// match-by-name-and-replace-or-append. Re-exported here so the two
1652/// production sites' `values_map.entry(Value::String(<key>.into()))` /
1653/// `programs_yaml.get(<key>)` navigation reads from the same
1654/// `&'static str` as every peer consumer (and every future fleet-
1655/// programs schema-key consumer — the M4 `app-operator` per-Aplicacao
1656/// reconciler, the future `feira app deploy --apply` writer-side
1657/// aggregator merge). Same re-export shape as the peer
1658/// [`KUBE_KEY_NAMESPACE`] / [`KUBE_KEY_METADATA`] / [`KUBE_KEY_SPEC`]
1659/// / [`KUBE_KEY_KIND`] / [`KUBE_KEY_API_VERSION`] surfaces on the
1660/// sibling K8s-CR canonical-key axes — extends the discipline the
1661/// K8s-CR key re-export quintet establishes onto the canonical
1662/// fleet-programs schema top-level axis.
1663pub use caixa_core::FLEET_PROGRAMS_KEY_PROGRAMS;
1664
1665/// Local re-export of [`caixa_core::FLEET_PROGRAMS_KEY_NAME`] — the
1666/// canonical `lareira-fleet-programs` values-schema per-entry name
1667/// discriminator key (`name:` — the exact YAML key the fleet-programs
1668/// library chart's `range .Values.programs` step reads per-entry to
1669/// key each rendered `ComputeUnit` CR's `metadata.name` off). Peer of
1670/// the sibling [`FLEET_PROGRAMS_KEY_PROGRAMS`] top-level array-key
1671/// re-export on the same fleet-programs schema — that one carries the
1672/// `programs:` array key both writer verbs upsert into, this one
1673/// carries the per-entry name-axis both writer verbs walk that array
1674/// by (and both emit-side entry builders — this crate's
1675/// [`programs_yaml_entry`] and the peer [`caixa_mesh::programs_for_aplicacao`]
1676/// — write the per-entry name-axis at).
1677///
1678/// This crate's three writer-side sites anchor on this key:
1679/// [`programs_yaml_entry`]'s emit-side `entry.insert(<key>.into(), …)`
1680/// call (seeding the per-entry name-axis from the Caixa's `nome`),
1681/// [`upsert_into_helmrelease_programs`]'s two `new_entry.get(<key>)`
1682/// / `slot.get(<key>)` navigations + `Error::MissingField(<key>)`
1683/// diagnostic on the aggregator-HelmRelease shape, and
1684/// [`upsert_into_programs_yaml`]'s peer three-site (extract + match +
1685/// `MissingField`) shape on the bare-values.yaml shape. All three
1686/// verbs now read from the same `&'static str` as every peer
1687/// consumer (and every future fleet-programs schema-key consumer —
1688/// the M4 `app-operator` per-Aplicacao reconciler, the future
1689/// `feira app deploy --apply` writer-side aggregator merge, the peer
1690/// [`caixa_mesh::programs_for_aplicacao`] per-`:membros` emit-side
1691/// name-axis). Same re-export shape as the peer
1692/// [`FLEET_PROGRAMS_KEY_PROGRAMS`] / [`KUBE_KEY_NAMESPACE`] /
1693/// [`KUBE_KEY_METADATA`] / [`KUBE_KEY_SPEC`] / [`KUBE_KEY_KIND`] /
1694/// [`KUBE_KEY_API_VERSION`] surfaces on the sibling fleet-programs /
1695/// K8s-CR canonical-key axes — extends the discipline the K8s-CR key
1696/// re-export quintet + the sibling fleet-programs top-level array-
1697/// key re-export establish onto the canonical fleet-programs schema
1698/// per-entry name-discriminator axis.
1699pub use caixa_core::FLEET_PROGRAMS_KEY_NAME;
1700
1701/// Local re-export of the canonical
1702/// [`caixa_core::COMPUTEUNIT_SPEC_KEY_MODULE`] — the
1703/// `wasm.pleme.io/v1alpha1/ComputeUnit` CRD per-CR wasm-module-reference
1704/// `spec.module` sub-block key every rendered `programs[]` entry
1705/// splices verbatim from the upstream ComputeUnit YAML's `spec.module`
1706/// (per the docstring on [`programs_yaml_entry`] above), so the
1707/// `lareira-fleet-programs` library chart's per-Servico module-source
1708/// axis binds to the exact source the caixa.lisp's `:servicos`
1709/// fixture pins. Four per-entry drift-detection navigators in this
1710/// crate's test module (the `programs_yaml_entry_round_trips` per-key
1711/// pair + the `upsert_helmrelease_replaces_existing` /
1712/// `upsert_into_programs_yaml` per-`module.source` navigators)
1713/// now consult the same `&'static str` as the peer caixa-helm
1714/// per-values navigators' module-source axis. Same re-export shape
1715/// as the peer [`FLEET_PROGRAMS_KEY_NAME`] / [`KUBE_KEY_NAMESPACE`]
1716/// surfaces on the sibling canonical-fleet-programs-schema-key /
1717/// canonical-K8s-CR-key axes — extends the discipline the M2-typed-
1718/// slot / fleet-programs schema / K8s-CR key re-export families
1719/// establish onto the substrate-side ComputeUnit-CRD per-`spec.*`
1720/// sub-block axis. See [`caixa_core::COMPUTEUNIT_SPEC_KEY_MODULE`]
1721/// for the full lift rationale.
1722pub use caixa_core::COMPUTEUNIT_SPEC_KEY_MODULE;
1723
1724/// Local re-export of the canonical
1725/// [`caixa_core::COMPUTEUNIT_SPEC_KEY_TRIGGER`] — the
1726/// `wasm.pleme.io/v1alpha1/ComputeUnit` CRD per-CR invocation-shape
1727/// `spec.trigger` sub-block key every rendered `programs[]` entry
1728/// splices verbatim from the upstream ComputeUnit YAML's
1729/// `spec.trigger`. Peer of [`COMPUTEUNIT_SPEC_KEY_MODULE`] on the same
1730/// ComputeUnit CRD per-`spec.*` sub-block axis. See
1731/// [`caixa_core::COMPUTEUNIT_SPEC_KEY_TRIGGER`] for the full lift
1732/// rationale.
1733pub use caixa_core::COMPUTEUNIT_SPEC_KEY_TRIGGER;
1734
1735/// Local re-export of the canonical
1736/// [`caixa_core::COMPUTEUNIT_SPEC_KEY_CAPABILITIES`] — the
1737/// `wasm.pleme.io/v1alpha1/ComputeUnit` CRD per-CR WASI-capability-list
1738/// `spec.capabilities` sub-block key every rendered `programs[]` entry
1739/// splices verbatim from the upstream ComputeUnit YAML's
1740/// `spec.capabilities`. Peer of [`COMPUTEUNIT_SPEC_KEY_MODULE`] and
1741/// [`COMPUTEUNIT_SPEC_KEY_TRIGGER`] on the same ComputeUnit CRD
1742/// per-`spec.*` sub-block axis — completes the substrate-side
1743/// ComputeUnit-CRD per-`spec.*` sub-block re-export triple in this
1744/// crate. See [`caixa_core::COMPUTEUNIT_SPEC_KEY_CAPABILITIES`] for
1745/// the full lift rationale.
1746pub use caixa_core::COMPUTEUNIT_SPEC_KEY_CAPABILITIES;
1747
1748/// Local re-export of the canonical
1749/// [`caixa_core::COMPUTEUNIT_MODULE_KEY_SOURCE`] — the
1750/// `wasm.pleme.io/v1alpha1/ComputeUnit` CRD nested
1751/// `spec.module.source` per-CR wasm-component-reference leaf-scalar
1752/// sub-block key every rendered `programs[]` entry carries under the
1753/// parent [`COMPUTEUNIT_SPEC_KEY_MODULE`] block to name the exact
1754/// OCI / git / file wasm-component artifact the M2.5 wasm-engine
1755/// instantiator loads at Servico bring-up. Three per-`module.source`
1756/// drift-detection navigators in this crate's test module
1757/// (`programs_yaml_entry_round_trips`'s per-entry
1758/// `.get(COMPUTEUNIT_SPEC_KEY_MODULE).and_then(|m| m.get(…))`
1759/// present-check + `upsert_into_programs_yaml`'s cross-upsert
1760/// readback + `upsert_into_helmrelease_programs`'s peer
1761/// `HelmRelease`-wrapped `spec.values.programs[]` cross-upsert
1762/// readback) now consult the same `&'static str` — extends the
1763/// discipline the peer [`COMPUTEUNIT_SPEC_KEY_MODULE`] /
1764/// [`COMPUTEUNIT_SPEC_KEY_TRIGGER`] / [`COMPUTEUNIT_SPEC_KEY_CAPABILITIES`]
1765/// top-level-`spec.*` re-exports establish one level deeper onto the
1766/// nested `spec.module.*` leaf-scalar-axis. See
1767/// [`caixa_core::COMPUTEUNIT_MODULE_KEY_SOURCE`] for the full lift
1768/// rationale.
1769pub use caixa_core::COMPUTEUNIT_MODULE_KEY_SOURCE;
1770
1771/// Local re-export of the canonical
1772/// [`caixa_core::servico_spec_and_m2_overlay_entries`] — the composed
1773/// per-Servico value-block splice helper this crate's
1774/// [`programs_yaml_entry`] and the peer
1775/// [`caixa_helm::build_values_yaml`] both now route their two-step
1776/// `spec.*` field-splice + M2 typed-slot overlay through. The single
1777/// production-code call site consuming it is
1778/// [`programs_yaml_entry`]'s inner splice loop (formerly two hand-
1779/// written for-loops chained around `string_keyed_entries` +
1780/// `servico_m2_overlay`); re-exported so the shared composition
1781/// contract lives in exactly one place across both per-Servico
1782/// renderers — a future author reading `caixa_flux::programs_yaml_entry`
1783/// finds the composition helper immediately without an extra `use
1784/// caixa_core::…` line, and a rebrand of the composition axis (e.g. a
1785/// swap of the `or_insert` precedence rule) reaches both renderers
1786/// through one canonical `&'static` function pointer. Same shape as
1787/// the peer render-side helper re-exports on the sibling
1788/// canonical-composed-primitive axes.
1789pub use caixa_core::servico_spec_and_m2_overlay_entries;
1790
1791/// Render a single `programs:[]` array entry for the cluster's
1792/// `lareira-fleet-programs` HelmRelease values.
1793///
1794/// The output is `serde_yaml::Value::Mapping`, so callers can splice
1795/// it into an existing `programs:` array without re-parsing the
1796/// containing structure. Schema is enforced by
1797/// `lareira-fleet-programs/values.schema.json` (`#/definitions/program`).
1798///
1799/// Pulls:
1800/// - `name` from `caixa.nome`
1801/// - `namespace` from `computeunit.metadata.namespace` (or `DEFAULT_NAMESPACE`)
1802/// - [`COMPUTEUNIT_SPEC_KEY_MODULE`] / [`COMPUTEUNIT_SPEC_KEY_TRIGGER`] /
1803/// [`COMPUTEUNIT_SPEC_KEY_CAPABILITIES`] / `config` / `resources`
1804/// from `computeunit.spec.*` (verbatim — schemas already match)
1805pub fn programs_yaml_entry(
1806 caixa: &Caixa,
1807 computeunit_yaml: &serde_yaml::Value,
1808) -> Result<serde_yaml::Value, Error> {
1809 caixa_core::require_v0_servico_shape::<Error>(caixa)?;
1810
1811 let spec = computeunit_yaml
1812 .get(KUBE_KEY_SPEC)
1813 .ok_or(Error::MissingField(KUBE_KEY_SPEC))?;
1814
1815 let namespace = kube_metadata_str_field(computeunit_yaml, KUBE_KEY_NAMESPACE)
1816 .unwrap_or(DEFAULT_NAMESPACE)
1817 .to_string();
1818
1819 let mut entry = serde_yaml::Mapping::new();
1820 // Route the per-entry `name:` `String`-carry through the typed
1821 // [`caixa_core::Caixa::nome`] accessor (`caixa.nome().to_string()`)
1822 // instead of the raw `caixa.nome.clone()` field access — sibling
1823 // convergence to the peer 54bf2f3 caixa-mesh
1824 // `programs_for_aplicacao` / `cilium_network_policies` /
1825 // `gateway_routes` three-site converge on the same axis on the
1826 // sibling renderer crate. Every future extension of the accessor
1827 // (an M4 namespace-qualified rewrite the CR materializer applies
1828 // per-CR, a per-cluster alias table pinned through a future
1829 // `:placement`-scoped slot, the `:nome-suffix` overlay
1830 // MESH-COMPOSITION §III.2 acknowledges) reaches this emit site
1831 // through the accessor by construction. Pinned by the drift-
1832 // detection test
1833 // [`programs_yaml_entry_name_field_routes_through_caixa_nome_accessor`]
1834 // in the tests module.
1835 entry.insert_string(FLEET_PROGRAMS_KEY_NAME, caixa.nome().to_string());
1836 entry.insert_string(KUBE_KEY_NAMESPACE, namespace);
1837
1838 // Two-step per-Servico value-block splice — the `spec.*` field
1839 // splice (module / trigger / capabilities / config / resources /
1840 // serviceAccount) and the M2 typed-slot overlay (limits / behavior
1841 // / upgradeFrom, `or_insert` semantics so `spec.*` wins on
1842 // collision) now route through the canonical
1843 // [`caixa_core::servico_spec_and_m2_overlay_entries`] composition
1844 // helper — the two prior inline for-loops chained around
1845 // `string_keyed_entries` + `servico_m2_overlay` this call site
1846 // (and the peer [`caixa_helm::build_values_yaml`] site) each
1847 // re-derived collapse onto one canonical composition, so a future
1848 // change to the per-Servico splice / overlay shape (the M4 typed
1849 // per-edge policy overlay slot addition MESH-COMPOSITION §III.2
1850 // #3 acknowledges, a change to the precedence rule once per-
1851 // Aplicacao operator overrides land, a canonicalization pass on
1852 // the merged key set) reaches both renderers by construction
1853 // instead of a coordinated two-file rewrite. See the helper's
1854 // docstring for the full lift rationale and the byte-shape
1855 // guarantee (spec.* keys preserved in source-Mapping insertion
1856 // order; M2 slots appended in canonical BTreeMap-key ordering at
1857 // every M2 key not already claimed by spec.*).
1858 for (k, v) in caixa_core::servico_spec_and_m2_overlay_entries(caixa, spec)? {
1859 entry.entry_str_key(&k).or_insert(v);
1860 }
1861
1862 Ok(serde_yaml::Value::Mapping(entry))
1863}
1864
1865/// Insert/upsert an entry into a `programs:` array nested under
1866/// the canonical fleet-manifest path: `spec.values.programs[]` in a
1867/// `HelmRelease` document. The pleme-io convention puts the fleet's
1868/// program list inside a HelmRelease (consumed by `lareira-fleet-programs`),
1869/// not at the top level. Same upsert semantics as
1870/// [`upsert_into_programs_yaml`] — match by `name`, replace in place,
1871/// otherwise append.
1872pub fn upsert_into_helmrelease_programs(
1873 helmrelease: serde_yaml::Value,
1874 new_entry: serde_yaml::Value,
1875) -> Result<(serde_yaml::Value, bool), Error> {
1876 let serde_yaml::Value::Mapping(mut root) = helmrelease else {
1877 return Err(Error::MissingField(
1878 "expected mapping at root of HelmRelease",
1879 ));
1880 };
1881
1882 let spec = root
1883 .get_mut(KUBE_KEY_SPEC)
1884 .ok_or(Error::MissingField(KUBE_KEY_SPEC))?;
1885 let serde_yaml::Value::Mapping(spec_map) = spec else {
1886 return Err(Error::MissingField("spec must be a mapping"));
1887 };
1888 let values_map = spec_map
1889 .entry_or_default_mapping(FLUX_KEY_VALUES)
1890 .ok_or(Error::MissingField("spec.values must be a mapping"))?;
1891 let arr = values_map
1892 .entry_or_default_sequence(FLEET_PROGRAMS_KEY_PROGRAMS)
1893 .ok_or(Error::MissingField(
1894 "spec.values.programs must be a sequence",
1895 ))?;
1896
1897 let inserted = caixa_core::upsert_named_entry(arr, new_entry, FLEET_PROGRAMS_KEY_NAME, || {
1898 Error::MissingField(FLEET_PROGRAMS_KEY_NAME)
1899 })?;
1900
1901 Ok((serde_yaml::Value::Mapping(root), inserted))
1902}
1903
1904/// Insert/upsert an entry into a `programs:` array of an existing
1905/// values.yaml structure.
1906///
1907/// Idempotent: if an entry with the same `name` exists, replaces it
1908/// in-place (preserving order). If not, appends. Returns the modified
1909/// document. Operates on `Value` so callers can round-trip via
1910/// `serde_yaml::from_str` / `to_string` without losing structure.
1911///
1912/// Returns the modified `programs_yaml` plus a `bool` indicating
1913/// whether the entry was a new insert (`true`) or a replacement (`false`).
1914pub fn upsert_into_programs_yaml(
1915 programs_yaml: serde_yaml::Value,
1916 new_entry: serde_yaml::Value,
1917) -> Result<(serde_yaml::Value, bool), Error> {
1918 let serde_yaml::Value::Mapping(mut root) = programs_yaml else {
1919 return Err(Error::MissingField(
1920 "expected mapping at root of values.yaml",
1921 ));
1922 };
1923
1924 let arr = root
1925 .entry_or_default_sequence(FLEET_PROGRAMS_KEY_PROGRAMS)
1926 .ok_or(Error::MissingField("programs must be a sequence"))?;
1927
1928 let inserted = caixa_core::upsert_named_entry(arr, new_entry, FLEET_PROGRAMS_KEY_NAME, || {
1929 Error::MissingField(FLEET_PROGRAMS_KEY_NAME)
1930 })?;
1931
1932 Ok((serde_yaml::Value::Mapping(root), inserted))
1933}
1934
1935// ── Cluster bundle (one-off / standalone path) ──────────────────────────
1936
1937/// Inputs for [`cluster_bundle`].
1938#[derive(Debug, Clone, Serialize, Deserialize)]
1939pub struct ClusterBundleOpts {
1940 /// Cluster name — drives output paths (e.g. `rio`, `mar`).
1941 pub cluster: String,
1942 /// Namespace for the rendered HelmRelease.
1943 pub namespace: String,
1944 /// Reconcile interval string (Helm/Flux duration like `"10m"`).
1945 pub interval: String,
1946 /// Path to the chart inside the source repo (default: `chart/`).
1947 pub chart_path: String,
1948 /// Source git URL.
1949 pub git_url: String,
1950 /// Source git ref (branch or tag).
1951 pub git_ref: GitRefSpec,
1952}
1953
1954#[derive(Debug, Clone, Serialize, Deserialize)]
1955#[serde(rename_all = "camelCase")]
1956pub enum GitRefSpec {
1957 Tag(String),
1958 Branch(String),
1959 Commit(String),
1960}
1961
1962impl GitRefSpec {
1963 /// The FluxCD source-controller `GitRepository.spec.ref.<field>`
1964 /// sub-selector scalar-axis key this variant renders under — the
1965 /// per-arm dispatch onto the canonical lifted
1966 /// [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
1967 /// [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] /
1968 /// [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] byte-string trio the
1969 /// caixa-core substrate owns.
1970 ///
1971 /// Both consumer sites in [`cluster_bundle`] (the `gitref_field`
1972 /// YAML emit-side composer and the sibling `tag_human`
1973 /// human-readable narrator prose) now route through this dispatch,
1974 /// closing the 2-site duplication of the prior inline
1975 /// `format!(" {arm}: {v:?}")` + `format!("{arm} {v}")` match
1976 /// blocks that each open-coded the three-way arm-shape mapping
1977 /// side-by-side. Same "one canonical dispatch per typed axis"
1978 /// discipline the peer [`caixa_core::WitTarget::payload_pair`]
1979 /// (6788ed6) established on the sibling `:contratos` payload-arm
1980 /// dispatch surface — a future `GitRefSpec` variant addition
1981 /// (FluxCD's source-controller `spec.ref` schema exposes further
1982 /// `semver` / `name` sub-selectors this V0 shape stops short of)
1983 /// becomes exactly one new match-arm here (a compile-time
1984 /// exhaustiveness error otherwise), not a coordinated three-way
1985 /// rewrite of both format-string templates + every downstream
1986 /// consumer that reaches for the per-arm sub-selector key.
1987 #[must_use]
1988 pub const fn ref_field_name(&self) -> &'static str {
1989 match self {
1990 GitRefSpec::Tag(_) => FLUX_GITREPOSITORY_REF_KEY_TAG,
1991 GitRefSpec::Branch(_) => FLUX_GITREPOSITORY_REF_KEY_BRANCH,
1992 GitRefSpec::Commit(_) => FLUX_GITREPOSITORY_REF_KEY_COMMIT,
1993 }
1994 }
1995
1996 /// The underlying scalar the variant carries — the tag / branch /
1997 /// commit value the FluxCD source-controller feeds into its
1998 /// per-CR git-source clone refspec. Peer of [`Self::ref_field_name`]
1999 /// on the same per-variant dispatch: both consumer sites in
2000 /// [`cluster_bundle`] pair the sub-selector key with the paired
2001 /// scalar to compose the rendered `spec.ref.<field>: <value>`
2002 /// YAML sub-block + the sibling `<field> <value>` narrator prose,
2003 /// so the pair moves together on any future variant addition.
2004 #[must_use]
2005 pub fn ref_value(&self) -> &str {
2006 match self {
2007 GitRefSpec::Tag(t) | GitRefSpec::Branch(t) | GitRefSpec::Commit(t) => t.as_str(),
2008 }
2009 }
2010}
2011
2012impl ClusterBundleOpts {
2013 /// Sensible defaults for a per-program standalone bundle.
2014 #[must_use]
2015 pub fn for_caixa(caixa: &Caixa, cluster: impl Into<String>) -> Self {
2016 Self {
2017 cluster: cluster.into(),
2018 namespace: DEFAULT_NAMESPACE.into(),
2019 interval: DEFAULT_FLUX_RECONCILE_INTERVAL.into(),
2020 chart_path: DEFAULT_FLUX_CHART_SOURCE_SUBPATH.into(),
2021 git_url: caixa.repositorio().map(str::to_owned).unwrap_or_else(|| {
2022 // Canonical typed `&str`-read of the per-`Caixa`
2023 // `:nome` universal-axis DNS-1123-label caixa-identity
2024 // scalar into the `:repositorio`-null pleme-org
2025 // github URL fallback composer. Peer of the sibling
2026 // 22461ef (caixa-helm) / 980c059 (caixa-mesh)
2027 // `caixa.nome()` converges on the co-resident
2028 // non-`.clone()` `&str`/Display raw-field-access axis
2029 // of `Caixa::nome` in the other two substrate-side
2030 // renderers and the sibling 4a363bf `caixa.nome().to_string()`
2031 // converge on the co-resident `String`-carry axis on
2032 // `Caixa::nome` in this crate — this extends the
2033 // "one typed dispatch on the substrate primitive,
2034 // thin projections at each consumer" discipline onto
2035 // the last unlifted non-`.clone()` raw-field-access
2036 // axis of `Caixa::nome` in caixa-flux, so every
2037 // substrate-side renderer (caixa-helm, caixa-flux,
2038 // caixa-mesh) now owns every projection of the
2039 // `Caixa::nome` axis through the typed accessor,
2040 // `.clone()` `String`-carry and `&str`/Display
2041 // raw-field-access alike.
2042 format!(
2043 "https://github.com/{org}/{nome}",
2044 org = caixa_core::DEFAULT_PLEME_GIT_ORG,
2045 nome = caixa.nome(),
2046 )
2047 }),
2048 git_ref: GitRefSpec::Tag(format!(
2049 "{prefix}{versao}",
2050 prefix = caixa_core::DEFAULT_PUBLISH_TAG_PREFIX,
2051 versao = caixa.versao(),
2052 )),
2053 }
2054 }
2055}
2056
2057/// One file of the cluster bundle — `(path, contents)` pair every
2058/// [`cluster_bundle`]-rendered Flux v2 CR YAML document lands at.
2059///
2060/// Type-aliased to the canonical [`caixa_core::RenderedFile`] so the
2061/// substrate-side "one rendered leaf artifact" shape lives at one
2062/// struct definition across every per-target renderer — the peer
2063/// [`caixa_helm::ChartFile`] alias resolves to the same canonical, so
2064/// a future rebrand on either axis (a per-artifact hash / provenance
2065/// field addition, a per-artifact write-mode discriminator once
2066/// per-cluster-writer sandboxing lands) lands at one caixa-core `pub
2067/// struct RenderedFile` edit and reaches both crates by construction.
2068/// Prior to this lift both crates carried an inline `pub struct
2069/// <Xxx>File { pub path: PathBuf, pub contents: String }` with
2070/// identical `#[derive(Debug, Clone, PartialEq, Eq)]` shapes and no
2071/// per-type impls; a future per-target renderer (`caixa-otel`, the
2072/// future `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer, the
2073/// future per-Supervisor reconciler renderer) would have carried a
2074/// third and fourth clone of the same record. Type aliases preserve
2075/// every existing struct-literal construction site
2076/// (`BundleFile { path, contents }`), every field-access site (`f.path`,
2077/// `f.contents`), and every derive-fed navigator by construction —
2078/// Rust type aliases inherit the aliased type's `#[derive]`-generated
2079/// `Debug`/`Clone`/`PartialEq`/`Eq` impls with no per-alias glue.
2080pub type BundleFile = caixa_core::RenderedFile;
2081
2082/// Cluster bundle: the FluxCD trio for a standalone caixa deploy.
2083///
2084/// Three YAMLs:
2085/// gitrepository.yaml — points at the caixa's source repo at a tag
2086/// helmrelease.yaml — uses the per-program chart from caixa-helm
2087/// kustomization.yaml — the Flux Kustomization that staples them
2088///
2089/// Written under `<cluster>/services/<caixa-name>/` by `feira deploy`.
2090///
2091/// V0 contract: every `:kind Servico` caixa carries exactly one
2092/// `:servicos` entry (one ComputeUnit YAML pointer per Servico,
2093/// matching the one `lareira-<nome>` Helm chart `caixa-helm` renders
2094/// and the one HelmRelease this bundle's `helmrelease.yaml` points at).
2095/// The pair [`caixa_core::require_kind`] + [`caixa_core::require_single_servico`]
2096/// is the canonical per-Servico-renderer entry-point gate axis the peer
2097/// [`programs_yaml_entry`] (the aggregator path) and
2098/// [`caixa_helm::render_chart_for_servico`] (the per-program chart path)
2099/// both run; until this gate landed `cluster_bundle` ran only the kind
2100/// half of the pair, so a Servico-kind caixa with a non-singleton
2101/// `:servicos` list silently passed the bundle render and the failure
2102/// surfaced at the chart-render layer (`caixa-helm` refused the input
2103/// with `UnsupportedServicoCount`) far from the source `caixa.lisp` and
2104/// far from the deploy-path entry point — the canonical "the V0
2105/// invariant is enforced at every per-Servico renderer entry except
2106/// this one" footgun the prior 06b2981 lift commit's body named when
2107/// it called the pair "the canonical V0-shape gate pair for the Servico
2108/// kind, in one place". Same shape every peer per-Servico-renderer
2109/// entry-point uses ([`programs_yaml_entry`] at the aggregator path,
2110/// [`caixa_helm::render_chart_for_servico`] at the per-program chart
2111/// path).
2112pub fn cluster_bundle(caixa: &Caixa, opts: &ClusterBundleOpts) -> Result<Vec<BundleFile>, Error> {
2113 caixa_core::require_v0_servico_shape::<Error>(caixa)?;
2114
2115 // Route the per-bundle `let name` `String`-carry through the typed
2116 // [`caixa_core::Caixa::nome`] accessor (`caixa.nome().to_string()`)
2117 // instead of the raw `caixa.nome.clone()` field access — the one
2118 // `let name` binding threads into every downstream
2119 // `metadata.name` axis this fn emits (the `GitRepository`
2120 // top-level `metadata.name`, the `HelmRelease` top-level
2121 // `metadata.name` + nested `spec.chart.spec.sourceRef.name`, the
2122 // `Kustomization` top-level `metadata.name` + nested
2123 // `spec.healthChecks[0].name`, plus the
2124 // [`flux_kustomization_source_subtree`] composer's per-caixa
2125 // sub-tree scalar), so this single accessor edit shifts every
2126 // per-CR name-axis derivation onto the typed dispatch at once.
2127 // Sibling convergence to the peer 54bf2f3 caixa-mesh three-site
2128 // converge on the same axis on the sibling renderer crate. Pinned
2129 // by the drift-detection tests
2130 // [`cluster_bundle_gitrepository_metadata_name_routes_through_caixa_nome_accessor`],
2131 // [`cluster_bundle_helmrelease_metadata_name_routes_through_caixa_nome_accessor`],
2132 // and
2133 // [`cluster_bundle_kustomization_metadata_name_routes_through_caixa_nome_accessor`]
2134 // in the tests module.
2135 let name = caixa.nome().to_string();
2136 let chart_name = lareira_chart_name(&name);
2137
2138 // The per-variant sub-selector key (`tag` / `branch` / `commit`)
2139 // + its paired scalar (the tag / branch / commit value) now route
2140 // through the canonical [`GitRefSpec::ref_field_name`] +
2141 // [`GitRefSpec::ref_value`] dispatch, closing the 2-site
2142 // duplication the prior inline per-variant `format!(" <arm>:
2143 // {v:?}")` match block open-coded side-by-side with the sibling
2144 // `tag_human` narrator prose block. Byte-identical output to the
2145 // prior 3-arm inline `format!`s: `{value:?}` on `&str` renders
2146 // the same shape as `{v:?}` on `String` (both call the same
2147 // `Debug` impl at the identical stack position).
2148 let gitref_field = format!(
2149 " {field}: {value:?}",
2150 field = opts.git_ref.ref_field_name(),
2151 value = opts.git_ref.ref_value(),
2152 );
2153
2154 let gitrepo = format!(
2155 "---\n\
2156 # Source — pinned to {tag_human}, rendered by caixa-flux.\n\
2157 {api_version_key}: {api_version}\n\
2158 {kind_key}: {kind}\n\
2159 {metadata_key}:\n \
2160 {name_key}: {name}\n \
2161 {namespace_key}: {namespace}\n\
2162 {spec_key}:\n \
2163 {interval_key}: {interval}\n \
2164 {url_key}: {url}\n \
2165 {ref_key}:\n\
2166 {gitref_field}\n",
2167 api_version_key = KUBE_KEY_API_VERSION,
2168 api_version = FLUX_GITREPOSITORY_API_VERSION,
2169 kind_key = KUBE_KEY_KIND,
2170 kind = FLUX_KIND_GIT_REPOSITORY,
2171 metadata_key = KUBE_KEY_METADATA,
2172 name_key = KUBE_KEY_NAME,
2173 namespace_key = KUBE_KEY_NAMESPACE,
2174 spec_key = KUBE_KEY_SPEC,
2175 tag_human = format!(
2176 "{field} {value}",
2177 field = opts.git_ref.ref_field_name(),
2178 value = opts.git_ref.ref_value(),
2179 ),
2180 name = name,
2181 namespace = opts.namespace,
2182 interval_key = FLUX_KEY_INTERVAL,
2183 interval = opts.interval,
2184 url_key = FLUX_GITREPOSITORY_KEY_URL,
2185 url = opts.git_url,
2186 ref_key = FLUX_GITREPOSITORY_KEY_REF,
2187 gitref_field = gitref_field,
2188 );
2189
2190 // The values wrap key under `spec.values.<library>:` must match the
2191 // peer caixa-helm chart's `dependencies[0].name` axis exactly —
2192 // Helm's per-dep alias convention scopes values under the
2193 // dependency's `name:` when no `alias:` is set, so a wrap-key drift
2194 // silently routes the per-cluster `enabled: true` override nowhere
2195 // at `helm template` / `helm install` time. Both axes now consult
2196 // the same lifted [`caixa_core::DEFAULT_LIBRARY_NAME`] constant
2197 // (`caixa-helm`'s `RenderOpts::library_name` defaults to the same
2198 // re-export), so a future per-edition library-chart rebrand reaches
2199 // both consumers through one `&'static str` by construction. Peer
2200 // with the [`DEFAULT_NAMESPACE`] (a085b26) /
2201 // [`DEFAULT_SERVICO_PORT`] (1e22add) lifts on the sibling
2202 // canonical-K8s-axis-constant surface — duplicated load-bearing
2203 // string axes lifted to one source of truth.
2204 let helmrelease = format!(
2205 "---\n\
2206 # HelmRelease consumes the chart caixa-helm renders for this\n\
2207 # caixa Servico. Per-cluster values are injected here.\n\
2208 {api_version_key}: {api_version}\n\
2209 {kind_key}: {kind}\n\
2210 {metadata_key}:\n \
2211 {name_key}: {name}\n \
2212 {namespace_key}: {namespace}\n\
2213 {spec_key}:\n \
2214 {interval_key}: {interval}\n \
2215 {chart_key}:\n \
2216 {spec_key}:\n \
2217 {chart_name_key}: {chart_path}\n \
2218 {source_ref_key}:\n \
2219 {kind_key}: {source_kind}\n \
2220 {name_key}: {name}\n \
2221 {namespace_key}: {namespace}\n \
2222 {install_key}:\n \
2223 {create_namespace_key}: {create_namespace_default}\n \
2224 {remediation_key}:\n \
2225 {retries_key}: {retries_default}\n \
2226 {upgrade_key}:\n \
2227 {remediation_key}:\n \
2228 {retries_key}: {retries_default}\n \
2229 {remediate_last_failure_key}: {remediate_last_failure_default}\n \
2230 {values_key}:\n \
2231 {library_name}:\n \
2232 {enabled_key}: {lareira_enabled_default}\n",
2233 api_version_key = KUBE_KEY_API_VERSION,
2234 api_version = FLUX_HELMRELEASE_API_VERSION,
2235 kind_key = KUBE_KEY_KIND,
2236 kind = FLUX_KIND_HELM_RELEASE,
2237 source_kind = FLUX_KIND_GIT_REPOSITORY,
2238 metadata_key = KUBE_KEY_METADATA,
2239 name_key = KUBE_KEY_NAME,
2240 namespace_key = KUBE_KEY_NAMESPACE,
2241 spec_key = KUBE_KEY_SPEC,
2242 name = name,
2243 namespace = opts.namespace,
2244 interval_key = FLUX_KEY_INTERVAL,
2245 interval = opts.interval,
2246 chart_key = FLUX_KEY_CHART,
2247 chart_name_key = FLUX_HELMCHART_TEMPLATE_KEY_CHART,
2248 chart_path = opts.chart_path,
2249 source_ref_key = FLUX_KEY_SOURCE_REF,
2250 values_key = FLUX_KEY_VALUES,
2251 library_name = DEFAULT_LIBRARY_NAME,
2252 enabled_key = HELM_VALUES_KEY_ENABLED,
2253 retries_default = FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT,
2254 retries_key = FLUX_HELMRELEASE_KEY_RETRIES,
2255 remediation_key = FLUX_HELMRELEASE_KEY_REMEDIATION,
2256 install_key = FLUX_HELMRELEASE_KEY_INSTALL,
2257 upgrade_key = FLUX_HELMRELEASE_KEY_UPGRADE,
2258 remediate_last_failure_key = FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE,
2259 remediate_last_failure_default = FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT,
2260 create_namespace_key = FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE,
2261 create_namespace_default = FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT,
2262 lareira_enabled_default = CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT,
2263 );
2264
2265 // The `spec.path` per-CR source-sub-tree scalar composes through
2266 // the canonical [`flux_kustomization_source_subtree`] helper
2267 // (re-exported from [`caixa_core::flux_kustomization_source_subtree`]),
2268 // so the substrate's canonical per-cluster / per-caixa GitRepository-
2269 // relative directory-tree seed (`./clusters/<cluster>/services/<nome>`)
2270 // lives at one composer instead of a verbatim inline
2271 // `format!("./clusters/{cluster}/services/{name}")` at this emit site.
2272 // Threaded through a `{source_subtree}` named-arg interpolation on
2273 // the paired `{path_key}` leaf-scalar-key emit. Peer to the sibling
2274 // [`caixa_core::oci_chart_ref`] / [`caixa_core::cilium_network_policy_name`]
2275 // / [`caixa_core::gateway_api_http_route_name`] canonical-composer
2276 // re-exports on the substrate-side canonical-load-bearing-scalar
2277 // axis.
2278 let source_subtree = flux_kustomization_source_subtree(&opts.cluster, &name);
2279
2280 let kustomization = format!(
2281 "---\n\
2282 # Flux Kustomization that pins the GitRepository + HelmRelease.\n\
2283 # Paired path: pleme-io/k8s/clusters/{cluster}/services/{name}/\n\
2284 {api_version_key}: {kustomization_api_version}\n\
2285 {kind_key}: {kind}\n\
2286 {metadata_key}:\n \
2287 {name_key}: {name}\n \
2288 {namespace_key}: {flux_system}\n\
2289 {spec_key}:\n \
2290 {interval_key}: {interval}\n \
2291 {prune_key}: {prune_default}\n \
2292 {source_ref_key}:\n \
2293 {kind_key}: {source_kind}\n \
2294 {name_key}: {flux_system}\n \
2295 {path_key}: {source_subtree}\n \
2296 {health_checks_key}:\n \
2297 - {api_version_key}: {api_version}\n \
2298 {kind_key}: {health_kind}\n \
2299 {name_key}: {name}\n \
2300 {namespace_key}: {namespace}\n \
2301 {timeout_key}: {timeout_default}\n",
2302 api_version_key = KUBE_KEY_API_VERSION,
2303 kustomization_api_version = FLUX_KUSTOMIZATION_API_VERSION,
2304 kind_key = KUBE_KEY_KIND,
2305 kind = FLUX_KIND_KUSTOMIZATION,
2306 source_kind = FLUX_KIND_GIT_REPOSITORY,
2307 health_kind = FLUX_KIND_HELM_RELEASE,
2308 metadata_key = KUBE_KEY_METADATA,
2309 name_key = KUBE_KEY_NAME,
2310 namespace_key = KUBE_KEY_NAMESPACE,
2311 spec_key = KUBE_KEY_SPEC,
2312 api_version = FLUX_HELMRELEASE_API_VERSION,
2313 name = name,
2314 namespace = opts.namespace,
2315 interval_key = FLUX_KEY_INTERVAL,
2316 interval = opts.interval,
2317 cluster = opts.cluster,
2318 flux_system = DEFAULT_FLUX_SYSTEM_NAMESPACE,
2319 source_ref_key = FLUX_KEY_SOURCE_REF,
2320 health_checks_key = FLUX_KEY_HEALTH_CHECKS,
2321 prune_key = FLUX_KUSTOMIZATION_KEY_PRUNE,
2322 prune_default = FLUX_KUSTOMIZATION_PRUNE_DEFAULT,
2323 path_key = FLUX_KUSTOMIZATION_KEY_PATH,
2324 timeout_key = FLUX_KUSTOMIZATION_KEY_TIMEOUT,
2325 timeout_default = DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT,
2326 source_subtree = source_subtree,
2327 );
2328 // chart_name is reserved for a future kustomization.yaml `resources:`
2329 // entry pointing at the rendered Chart.yaml; not yet wired.
2330 let _ = chart_name;
2331
2332 // Each per-CR YAML leaf routes through the canonical
2333 // [`caixa_core::RenderedFile::new`] `impl Into<PathBuf>` /
2334 // `impl Into<String>` constructor (re-exported by the peer
2335 // [`BundleFile`] alias since Rust inherent methods travel through
2336 // type aliases to the aliased type at name resolution). The prior
2337 // three inline `BundleFile { path: std::path::PathBuf::from(
2338 // FILENAME_CONST), contents: <body> }` blocks each re-derived the
2339 // same `PathBuf::from(&str)` wrap + the same two-field assembly —
2340 // a byte-identical duplicate of the peer
2341 // [`caixa_helm::render_chart_for_servico_with`] `Chart.yaml` /
2342 // `values.yaml` / `README.md` chart-directory trio's three
2343 // per-artifact emit sites. Sweeping both trios onto
2344 // [`RenderedFile::new`] collapses the six substrate-side
2345 // per-artifact-construction sites onto one canonical constructor
2346 // so a future rebrand on the record shape (a per-artifact hash /
2347 // provenance field addition, a per-artifact write-mode discriminator
2348 // once per-cluster-writer sandboxing lands, the
2349 // [`caixa_core::is_sandboxed_relative_path`] discipline the
2350 // [`caixa_core::RenderedFile`] docstring acknowledges is not yet
2351 // run at emit time) reaches every per-target renderer through one
2352 // caixa-core edit instead of a coordinated six-site rewrite.
2353 Ok(vec![
2354 BundleFile::new(FLUX_GITREPOSITORY_YAML_FILENAME, gitrepo),
2355 BundleFile::new(FLUX_HELMRELEASE_YAML_FILENAME, helmrelease),
2356 BundleFile::new(FLUX_KUSTOMIZATION_YAML_FILENAME, kustomization),
2357 ])
2358}
2359
2360#[cfg(test)]
2361mod tests {
2362 use super::*;
2363 use caixa_core::{
2364 Caixa, CaixaKind, M2_BEHAVIOR_KEY_ON_INIT, M2_KEY_BEHAVIOR, M2_KEY_LIMITS,
2365 M2_KEY_UPGRADE_FROM, M2_LIMITS_KEY_CPU, M2_LIMITS_KEY_MEMORY, M2_UPGRADE_FROM_KEY_FROM,
2366 kube_root_str_field,
2367 };
2368
2369 fn sample_caixa() -> Caixa {
2370 Caixa {
2371 nome: "hello-rio".into(),
2372 versao: "0.1.0".into(),
2373 kind: CaixaKind::Servico,
2374 edicao: Some("2026".into()),
2375 descricao: Some("Canonical Rust→wasm32-wasip2 caixa Servico.".into()),
2376 repositorio: Some("https://github.com/pleme-io/hello-rio".into()),
2377 licenca: Some("MIT".into()),
2378 autores: vec!["pleme-io".into()],
2379 etiquetas: vec!["hello-world".into()],
2380 deps: vec![],
2381 deps_dev: vec![],
2382 exe: vec![],
2383 bibliotecas: vec![],
2384 servicos: vec!["servicos/hello-rio.computeunit.yaml".into()],
2385 limits: None,
2386 behavior: None,
2387 upgrade_from: vec![],
2388 estrategia: None,
2389 max_restarts: None,
2390 restart_window: None,
2391 children: vec![],
2392 membros: vec![],
2393 contratos: vec![],
2394 politicas: None,
2395 placement: None,
2396 entrada: None,
2397 ci: None,
2398 }
2399 }
2400
2401 fn sample_cu_yaml() -> serde_yaml::Value {
2402 serde_yaml::from_str(
2403 r#"
2404apiVersion: wasm.pleme.io/v1alpha1
2405kind: ComputeUnit
2406metadata:
2407 name: hello-rio
2408 namespace: tatara-system
2409spec:
2410 module:
2411 source: oci://ghcr.io/pleme-io/hello-rio:v0.1.0
2412 trigger:
2413 service:
2414 port: 8080
2415 paths: ["/", "/hello", "/healthz"]
2416 capabilities:
2417 - http-in:0.0.0.0:8080
2418 - env
2419"#,
2420 )
2421 .unwrap()
2422 }
2423
2424 #[test]
2425 fn default_namespace_re_export_points_at_caixa_core_canonical() {
2426 // The renderer's `pub const DEFAULT_NAMESPACE` was lifted to a
2427 // re-export of [`caixa_core::DEFAULT_NAMESPACE`] so the
2428 // namespace string lives in exactly one place across every
2429 // caixa renderer (caixa-flux + caixa-mesh today, every future
2430 // per-target renderer the substrate adds). Pin the equality
2431 // here so any local re-introduction of a sibling `pub const
2432 // DEFAULT_NAMESPACE: &str = "…"` (the canonical drift footgun
2433 // that motivated this lift, with the prior caixa-mesh doc-
2434 // comment explicitly acknowledging the duplication) is a
2435 // build-time test failure naming the offending drift, not a
2436 // silent apply-time CiliumNetworkPolicy / Gateway / HTTPRoute
2437 // `endpointSelector` namespace mismatch dropping every L7
2438 // contrato flow far from the source rebrand commit. Peer to
2439 // `caixa_mesh::tests::default_namespace_re_export_points_at_caixa_core_canonical`
2440 // on the sibling renderer crate.
2441 caixa_core::assert_str_reexport_identity(
2442 "DEFAULT_NAMESPACE",
2443 DEFAULT_NAMESPACE,
2444 caixa_core::DEFAULT_NAMESPACE,
2445 );
2446 }
2447
2448 #[test]
2449 fn default_flux_reconcile_interval_re_export_points_at_caixa_core_canonical() {
2450 // The renderer's `DEFAULT_FLUX_RECONCILE_INTERVAL` was lifted
2451 // from the inline `"10m"` scalar-value literal at
2452 // [`ClusterBundleOpts::for_caixa`]'s per-caixa default seed (the
2453 // sole production-code site the substrate seeds into the
2454 // [`ClusterBundleOpts::interval`] field that [`cluster_bundle`]'s
2455 // three per-CR format-string templates thread through their
2456 // [`FLUX_KEY_INTERVAL`]-keyed `spec.interval` axis verbatim) to a
2457 // re-export of [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] so
2458 // the Flux v2 controller-side reconcile-cadence default scalar-
2459 // value string lives in exactly one place across every caixa
2460 // renderer. Pin the equality + static-data identity here so any
2461 // local re-introduction of a sibling `pub const
2462 // DEFAULT_FLUX_RECONCILE_INTERVAL: &str = "…"` (the canonical
2463 // drift footgun where a sibling local `pub const` could happen
2464 // to carry the same string at the source while pointing at a
2465 // different `&'static` allocation) is a build-time test failure
2466 // naming the offending drift, not a silent apply-time symptom —
2467 // the prior inline shape would have let a substrate-side
2468 // reconcile-cadence migration without a coordinated caixa-core
2469 // edit silently seed per-caixa Flux v2 CRs at a drifted per-CR
2470 // reconcile-schedule, splitting the substrate's per-caixa
2471 // convergence-freshness contract across renderer versions with
2472 // no diagnostic naming the cadence-drift root cause. Peer to
2473 // [`default_namespace_re_export_points_at_caixa_core_canonical`]
2474 // on the sibling canonical-substrate-default-load-bearing-
2475 // scalar re-export surface.
2476 caixa_core::assert_str_reexport_identity(
2477 "DEFAULT_FLUX_RECONCILE_INTERVAL",
2478 DEFAULT_FLUX_RECONCILE_INTERVAL,
2479 caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL,
2480 );
2481 }
2482
2483 #[test]
2484 fn cluster_bundle_opts_for_caixa_seeds_interval_from_lifted_default() {
2485 // Fail-before-pass-after pin: the substrate's per-caixa default
2486 // seed for [`ClusterBundleOpts::interval`] must resolve to the
2487 // lifted [`DEFAULT_FLUX_RECONCILE_INTERVAL`] verbatim. Before the
2488 // lift the field carried an inline `"10m"` literal at the sole
2489 // production-code call site (the [`ClusterBundleOpts::for_caixa`]
2490 // per-caixa default builder); a future substrate-side
2491 // reconcile-cadence migration on the canonical
2492 // [`caixa_core::DEFAULT_FLUX_RECONCILE_INTERVAL`] declaration
2493 // that failed to reach this seed site would silently split the
2494 // substrate's per-caixa Flux v2 convergence-freshness contract
2495 // between the operator-facing canonical default and the per-
2496 // caixa `cluster_bundle` renderer's seeded reconcile-schedule,
2497 // freezing every per-caixa Flux v2 CR at the drifted cadence
2498 // far from the rebrand commit's source. Pin the identity here
2499 // so a regression that re-introduces an inline literal at the
2500 // seed site surfaces at build time on this test's failure. Peer
2501 // to the sibling
2502 // [`cluster_bundle_every_flux_cr_carries_lifted_flux_key_interval_scalar`]
2503 // pin on the per-CR `spec.interval` axis — that test pins the
2504 // rendered scalar agrees with `opts.interval`, this test pins
2505 // `opts.interval`'s substrate-side seed agrees with the lifted
2506 // canonical default.
2507 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
2508 assert_eq!(
2509 opts.interval, DEFAULT_FLUX_RECONCILE_INTERVAL,
2510 "the substrate's per-caixa Flux v2 reconcile-cadence default \
2511 seed must resolve to the lifted \
2512 `DEFAULT_FLUX_RECONCILE_INTERVAL` scalar — drift here \
2513 silently splits the substrate's per-caixa convergence-\
2514 freshness contract between the operator-facing canonical \
2515 default and the per-caixa seeded reconcile-schedule"
2516 );
2517 }
2518
2519 #[test]
2520 fn default_flux_chart_source_subpath_re_export_points_at_caixa_core_canonical() {
2521 // The renderer's `DEFAULT_FLUX_CHART_SOURCE_SUBPATH` was lifted
2522 // from the inline `"chart".into()` scalar-value literal at
2523 // [`ClusterBundleOpts::for_caixa`]'s per-caixa default seed (the
2524 // sole production-code site the substrate seeds into the
2525 // [`ClusterBundleOpts::chart_path`] field that [`cluster_bundle`]'s
2526 // `helmrelease.yaml` format-string template threads through its
2527 // [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`]-keyed `spec.chart.spec.chart`
2528 // axis verbatim) to a re-export of
2529 // [`caixa_core::DEFAULT_FLUX_CHART_SOURCE_SUBPATH`] so the Flux v2
2530 // helm-controller-side chart-directory-in-GitRepository-source
2531 // default scalar-value string lives in exactly one place across
2532 // every caixa renderer. Pin the equality + static-data identity
2533 // here so any local re-introduction of a sibling `pub const
2534 // DEFAULT_FLUX_CHART_SOURCE_SUBPATH: &str = "…"` (the canonical
2535 // drift footgun where a sibling local `pub const` could happen to
2536 // carry the same string at the source while pointing at a
2537 // different `&'static` allocation) is a build-time test failure
2538 // naming the offending drift, not a silent apply-time symptom —
2539 // the prior inline shape would have let a substrate-side chart-
2540 // directory-in-git-source migration without a coordinated caixa-
2541 // core edit silently seed per-caixa `HelmRelease` CRs at a
2542 // drifted per-CR chart-directory pointer, splitting the
2543 // substrate's per-caixa chart-open contract with the Flux v2
2544 // helm-controller across renderer versions with no diagnostic
2545 // naming the sub-path-drift root cause (the source-controller
2546 // would then either fail to open the paired per-caixa chart
2547 // directory or, worse, silently open a stale sibling directory
2548 // the drifted scalar happens to name). Peer to
2549 // [`default_flux_reconcile_interval_re_export_points_at_caixa_core_canonical`]
2550 // on the sibling canonical-substrate-default-load-bearing-
2551 // scalar re-export surface.
2552 caixa_core::assert_str_reexport_identity(
2553 "DEFAULT_FLUX_CHART_SOURCE_SUBPATH",
2554 DEFAULT_FLUX_CHART_SOURCE_SUBPATH,
2555 caixa_core::DEFAULT_FLUX_CHART_SOURCE_SUBPATH,
2556 );
2557 }
2558
2559 #[test]
2560 fn cluster_bundle_opts_for_caixa_seeds_chart_path_from_lifted_default() {
2561 // Fail-before-pass-after pin: the substrate's per-caixa default
2562 // seed for [`ClusterBundleOpts::chart_path`] must resolve to the
2563 // lifted [`DEFAULT_FLUX_CHART_SOURCE_SUBPATH`] verbatim. Before
2564 // the lift the field carried an inline `"chart".into()` literal
2565 // at the sole production-code call site (the
2566 // [`ClusterBundleOpts::for_caixa`] per-caixa default builder); a
2567 // future substrate-side chart-directory-in-git-source migration
2568 // on the canonical
2569 // [`caixa_core::DEFAULT_FLUX_CHART_SOURCE_SUBPATH`] declaration
2570 // that failed to reach this seed site would silently split the
2571 // substrate's per-caixa Flux v2 chart-open contract between the
2572 // operator-facing canonical default and the per-caixa
2573 // `cluster_bundle` renderer's seeded chart-directory pointer,
2574 // freezing every per-caixa `HelmRelease` CR at the drifted sub-
2575 // path far from the rebrand commit's source. Pin the identity
2576 // here so a regression that re-introduces an inline literal at
2577 // the seed site surfaces at build time on this test's failure.
2578 // Peer to the sibling
2579 // [`cluster_bundle_opts_for_caixa_seeds_interval_from_lifted_default`]
2580 // pin on the co-resident per-caixa Flux v2 CR substrate-default
2581 // seed surface — that test pins `opts.interval`'s substrate-side
2582 // seed agrees with the lifted canonical default, this test pins
2583 // `opts.chart_path`'s substrate-side seed agrees with the peer
2584 // lifted canonical default.
2585 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
2586 assert_eq!(
2587 opts.chart_path, DEFAULT_FLUX_CHART_SOURCE_SUBPATH,
2588 "the substrate's per-caixa Flux v2 chart-directory-in-git-\
2589 source default seed must resolve to the lifted \
2590 `DEFAULT_FLUX_CHART_SOURCE_SUBPATH` scalar — drift here \
2591 silently splits the substrate's per-caixa chart-open \
2592 contract between the operator-facing canonical default \
2593 and the per-caixa seeded chart-directory pointer"
2594 );
2595 }
2596
2597 #[test]
2598 fn cluster_bundle_opts_for_caixa_git_url_fallback_routes_through_caixa_nome_accessor() {
2599 // Fail-before-pass-after pin: the substrate's per-caixa
2600 // `:repositorio`-null pleme-org github URL fallback composer
2601 // inside [`ClusterBundleOpts::for_caixa`] must derive its
2602 // trailing `<nome>` path segment through the typed
2603 // [`caixa_core::Caixa::nome`] accessor, not the raw
2604 // `caixa.nome` field access. Before this converge the
2605 // fallback branch carried a raw `nome = caixa.nome` Display
2606 // of the underlying `String` field into the `format!("https://\
2607 // github.com/{org}/{nome}", ...)` template, bypassing the
2608 // typed dispatch every peer per-Caixa identity consumer in
2609 // caixa-helm / caixa-mesh already routes through — the
2610 // canonical drift-footgun shape where a future
2611 // `Caixa::nome`-accessor extension (a per-cluster alias
2612 // table the operator pins through a future `:placement`-
2613 // scoped slot, an M4 namespace-qualified rewrite the CR
2614 // materializer applies per-CR, the future `:nome-suffix`
2615 // overlay MESH-COMPOSITION §III.2 acknowledges) would land
2616 // on the accessor but never reach this emit site, silently
2617 // splitting the parent-Caixa identity between the
2618 // FluxCD `GitRepository` `spec.url` `<org>/<nome>` clone
2619 // target this fallback composes and every other per-Caixa
2620 // identity consumer the caixa-helm / caixa-mesh renderers
2621 // emit — the source-controller would then clone from a
2622 // wrong-name pleme-org repository, silently freezing every
2623 // `:repositorio`-null caixa's Flux v2 clone target at the
2624 // pre-extension name and orphaning the paired `HelmRelease`
2625 // `chart: sourceRef` from the actual per-caixa git source
2626 // the substrate resolves through the accessor. Pin the
2627 // equality on the constructed `opts.git_url` so a regression
2628 // that re-inlines `caixa.nome` at the fallback site
2629 // surfaces here as a build-time test failure rather than as
2630 // a silent deploy-time `GitRepository` reconcile loop. Peer
2631 // to the sibling `cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`
2632 // pin on the co-resident `git_ref` axis of the same
2633 // `ClusterBundleOpts::for_caixa` composer surface, and to
2634 // the sibling 22461ef (caixa-helm) / 980c059 (caixa-mesh)
2635 // `caixa.nome()` converge pins on the peer non-`.clone()`
2636 // raw-field-access axis of `Caixa::nome` in the other two
2637 // substrate-side renderers.
2638 let mut caixa = sample_caixa();
2639 caixa.repositorio = None;
2640 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
2641 let expected = format!(
2642 "https://github.com/{org}/{nome}",
2643 org = caixa_core::DEFAULT_PLEME_GIT_ORG,
2644 nome = caixa.nome(),
2645 );
2646 assert_eq!(
2647 opts.git_url, expected,
2648 "the substrate's per-caixa `:repositorio`-null pleme-org \
2649 github URL fallback composer must derive its trailing \
2650 `<nome>` path segment through the typed \
2651 `caixa_core::Caixa::nome` accessor — a regression that \
2652 re-inlines `caixa.nome` at the fallback site silently \
2653 splits the parent-Caixa identity between the FluxCD \
2654 `GitRepository` `spec.url` `<org>/<nome>` clone target \
2655 and every other per-Caixa identity consumer the sibling \
2656 caixa-helm / caixa-mesh renderers emit"
2657 );
2658 }
2659
2660 #[test]
2661 fn flux_helmrelease_remediation_retries_default_re_export_points_at_caixa_core_canonical() {
2662 // The renderer's `FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`
2663 // was lifted from the two production-code duplicated inline
2664 // `retries: 3` scalar-value literals inside [`cluster_bundle`]'s
2665 // `helmrelease.yaml` format-string template (the install-path
2666 // `install.remediation.retries` site + the upgrade-path
2667 // `upgrade.remediation.retries` site) to a re-export of
2668 // [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] so
2669 // the Flux v2 helm-controller-side per-CR remediation-retries
2670 // default scalar-value lives in exactly one place across every
2671 // caixa renderer. Pin the equality here so any local
2672 // re-introduction of a sibling `pub const
2673 // FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT: u32 = <n>` (the
2674 // canonical drift footgun where a sibling local `pub const`
2675 // could happen to carry a different value while the rest of the
2676 // codebase keeps consuming the caixa-core canonical) is a
2677 // build-time test failure naming the offending drift, not a
2678 // silent apply-time symptom — the prior duplicated inline shape
2679 // would have let a substrate-side retry-ceiling migration on the
2680 // canonical caixa-core declaration without a coordinated caixa-
2681 // flux edit silently seed per-caixa Flux v2 `HelmRelease` CRs at
2682 // a drifted per-path remediation-retries schedule, splitting the
2683 // substrate's canonical retry-ceiling between the install-path
2684 // and the upgrade-path with no diagnostic naming the ceiling-
2685 // drift root cause. Peer to
2686 // [`default_flux_reconcile_interval_re_export_points_at_caixa_core_canonical`]
2687 // on the sibling canonical-substrate-default-load-bearing-scalar
2688 // re-export surface.
2689 assert_eq!(
2690 FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT,
2691 caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT,
2692 "`caixa_flux::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT` \
2693 must be the value-identical re-export of the canonical \
2694 `caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT` — \
2695 drift here silently splits the substrate's per-caixa Flux \
2696 v2 `HelmRelease` remediation-retries ceiling between the \
2697 canonical caixa-core declaration and the renderer's threaded \
2698 seed"
2699 );
2700 }
2701
2702 #[test]
2703 fn flux_helmrelease_key_retries_re_export_points_at_caixa_core_canonical() {
2704 // The renderer's `pub use caixa_core::FLUX_HELMRELEASE_KEY_RETRIES`
2705 // is the single source of truth for the Flux v2 per-CR
2706 // remediation-retries leaf-scalar-key baked into both the
2707 // install-path + upgrade-path `retries:` sub-block leaf-headers
2708 // of the [`cluster_bundle`] `helmrelease.yaml` format-string
2709 // template (both threading the same `&'static str` through the
2710 // new `{retries_key}` named-arg interpolation) plus the two
2711 // test-fixture navigation sites in `mod tests` that probe the
2712 // rendered document at `.get(FLUX_HELMRELEASE_KEY_RETRIES)`. Pin
2713 // the equality (and the static-data identity, peer with the
2714 // sibling
2715 // [`flux_helmrelease_remediation_retries_default_re_export_points_at_caixa_core_canonical`]
2716 // pin on the scalar-value half of the same
2717 // `(leaf-key, scalar-value)` per-path retry-cap declaration
2718 // pair) so any local re-introduction of a sibling
2719 // `pub const FLUX_HELMRELEASE_KEY_RETRIES: &str = "…"` (the
2720 // canonical drift footgun this lift closes — the load-bearing
2721 // Flux-v2-helm-controller-side per-CR remediation-retries leaf-
2722 // scalar-key across four prior inlined occurrences — two
2723 // production emit sites in the `cluster_bundle` `helmrelease.yaml`
2724 // format-string template plus two test-fixture navigation sites,
2725 // lifted to one re-export at the caixa-core boundary) is a
2726 // build-time test failure naming the offending drift, not a
2727 // silent apply-time symptom (a stripped `retries:` leaf letting
2728 // the helm-controller fall back to the Flux v2 upstream default).
2729 assert_eq!(
2730 FLUX_HELMRELEASE_KEY_RETRIES,
2731 caixa_core::FLUX_HELMRELEASE_KEY_RETRIES
2732 );
2733 assert!(
2734 std::ptr::eq(
2735 FLUX_HELMRELEASE_KEY_RETRIES.as_ptr(),
2736 caixa_core::FLUX_HELMRELEASE_KEY_RETRIES.as_ptr(),
2737 ),
2738 "FLUX_HELMRELEASE_KEY_RETRIES must be a re-export of \
2739 caixa_core::FLUX_HELMRELEASE_KEY_RETRIES, not a sibling `pub const` \
2740 that happens to carry the same string — drift between the two is \
2741 the canonical footgun this lift closes"
2742 );
2743 }
2744
2745 #[test]
2746 fn flux_helmrelease_key_remediation_re_export_points_at_caixa_core_canonical() {
2747 // The renderer's `pub use caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATION`
2748 // is the single source of truth for the Flux v2 per-CR
2749 // remediation sub-container-axis-key baked into both the
2750 // install-path + upgrade-path `remediation:` sub-block-header
2751 // lines of the [`cluster_bundle`] `helmrelease.yaml` format-
2752 // string template (both threading the same `&'static str`
2753 // through the new `{remediation_key}` named-arg interpolation)
2754 // plus the two test-fixture navigation sites in `mod tests` that
2755 // probe the rendered document at
2756 // `.get(FLUX_HELMRELEASE_KEY_REMEDIATION)`. Pin the equality
2757 // (and the static-data identity, peer with the sibling
2758 // [`flux_helmrelease_key_retries_re_export_points_at_caixa_core_canonical`]
2759 // pin on the leaf-scalar-key half of the same
2760 // `(container-axis-key, leaf-scalar-key, scalar-value)` per-path
2761 // retry-cap declaration triple) so any local re-introduction of
2762 // a sibling `pub const FLUX_HELMRELEASE_KEY_REMEDIATION: &str =
2763 // "…"` (the canonical drift footgun this lift closes — the
2764 // load-bearing Flux-v2-helm-controller-side per-CR remediation
2765 // sub-container-axis-key across four prior inlined occurrences —
2766 // two production emit sites in the `cluster_bundle`
2767 // `helmrelease.yaml` format-string template plus two test-
2768 // fixture navigation sites, lifted to one re-export at the
2769 // caixa-core boundary) is a build-time test failure naming the
2770 // offending drift, not a silent apply-time symptom (a stripped
2771 // whole-remediation sub-block letting the helm-controller fall
2772 // back to the Flux v2 upstream defaults for the whole per-path
2773 // remediation surface).
2774 caixa_core::assert_str_reexport_identity(
2775 "FLUX_HELMRELEASE_KEY_REMEDIATION",
2776 FLUX_HELMRELEASE_KEY_REMEDIATION,
2777 caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATION,
2778 );
2779 }
2780
2781 #[test]
2782 fn flux_helmrelease_key_remediation_pins_canonical_remediation_string() {
2783 // Bridge-arm pin: the lifted [`FLUX_HELMRELEASE_KEY_REMEDIATION`]
2784 // constant resolves to the canonical `"remediation"` string
2785 // today, and both rendered Flux v2 `HelmRelease` per-path per-CR
2786 // sub-block-headers must spell it out verbatim. Pin the literal
2787 // here (peer with the sibling
2788 // [`flux_helmrelease_key_retries_pins_canonical_retries_string`]-shape
2789 // canonical-default arm on the sibling per-CR leaf-scalar-key
2790 // surface + the peer
2791 // [`flux_key_source_ref_pins_canonical_source_ref_string`]-shape
2792 // canonical-default arm on the peer per-CR container-axis-key
2793 // surface) so a future rebrand of the lifted constant (Flux v3
2794 // rename like `recovery` / `retryPolicy` / `errorHandling` —
2795 // upstream Flux v3 roadmap candidates that would land the same
2796 // per-CR retry-cap semantics under a different sub-container-
2797 // axis-key) surfaces here as a coordinated edit-point.
2798 assert_eq!(FLUX_HELMRELEASE_KEY_REMEDIATION, "remediation");
2799 }
2800
2801 #[test]
2802 fn flux_helmrelease_key_install_re_export_points_at_caixa_core_canonical() {
2803 // The renderer's `pub use caixa_core::FLUX_HELMRELEASE_KEY_INSTALL`
2804 // is the single source of truth for the Flux v2 per-CR install-
2805 // path helm-action-phase discriminator parent-container-axis-key
2806 // baked into the `install:` sub-block-header line of the
2807 // [`cluster_bundle`] `helmrelease.yaml` format-string template
2808 // (threading the same `&'static str` through the new
2809 // `{install_key}` named-arg interpolation) plus the one test-
2810 // fixture navigation site in `mod tests` that probes the
2811 // rendered document at `.get(FLUX_HELMRELEASE_KEY_INSTALL)`. Pin
2812 // the equality (and the static-data identity, peer with the
2813 // sibling
2814 // [`flux_helmrelease_key_remediation_re_export_points_at_caixa_core_canonical`]
2815 // pin on the sub-container-axis-key half of the same
2816 // `(parent-container-key, sub-container-key, leaf-key, scalar-
2817 // value)` per-path retry-cap declaration quartet) so any local
2818 // re-introduction of a sibling `pub const
2819 // FLUX_HELMRELEASE_KEY_INSTALL: &str = "…"` (the canonical drift
2820 // footgun this lift closes — the load-bearing Flux-v2-helm-
2821 // controller-side per-CR install-path phase-discriminator
2822 // parent-container-axis-key across two prior inlined occurrences —
2823 // one production emit site in the `cluster_bundle`
2824 // `helmrelease.yaml` format-string template plus one test-
2825 // fixture navigation site, lifted to one re-export at the caixa-
2826 // core boundary) is a build-time test failure naming the
2827 // offending drift, not a silent apply-time symptom (a stripped
2828 // whole-install-path per-CR phase block letting the helm-
2829 // controller fall back to the Flux v2 upstream defaults for the
2830 // whole install-path phase surface).
2831 caixa_core::assert_str_reexport_identity(
2832 "FLUX_HELMRELEASE_KEY_INSTALL",
2833 FLUX_HELMRELEASE_KEY_INSTALL,
2834 caixa_core::FLUX_HELMRELEASE_KEY_INSTALL,
2835 );
2836 }
2837
2838 #[test]
2839 fn flux_helmrelease_key_install_pins_canonical_install_string() {
2840 // Bridge-arm pin: the lifted [`FLUX_HELMRELEASE_KEY_INSTALL`]
2841 // constant resolves to the canonical `"install"` string today,
2842 // and the rendered Flux v2 `HelmRelease` per-CR install-path
2843 // phase sub-block-header must spell it out verbatim. Pin the
2844 // literal here (peer with the sibling
2845 // [`flux_helmrelease_key_remediation_pins_canonical_remediation_string`]-shape
2846 // canonical-default arm on the sibling per-CR sub-container-
2847 // axis-key surface + the sibling
2848 // [`flux_helmrelease_key_retries_pins_canonical_retries_string`]-shape
2849 // canonical-default arm on the sibling per-CR leaf-scalar-key
2850 // surface) so a future rebrand of the lifted constant (Flux v3
2851 // rename like `initialize` / `apply` / `create` / `first-run` —
2852 // upstream Flux v3 roadmap candidates that would land the same
2853 // per-CR first-time chart apply phase semantics under a
2854 // different parent-container-axis-key) surfaces here as a
2855 // coordinated edit-point.
2856 assert_eq!(FLUX_HELMRELEASE_KEY_INSTALL, "install");
2857 }
2858
2859 #[test]
2860 fn flux_helmrelease_key_upgrade_re_export_points_at_caixa_core_canonical() {
2861 // The renderer's `pub use caixa_core::FLUX_HELMRELEASE_KEY_UPGRADE`
2862 // is the single source of truth for the Flux v2 per-CR upgrade-
2863 // path helm-action-phase discriminator parent-container-axis-key
2864 // baked into the `upgrade:` sub-block-header line of the
2865 // [`cluster_bundle`] `helmrelease.yaml` format-string template
2866 // (threading the same `&'static str` through the new
2867 // `{upgrade_key}` named-arg interpolation) plus the one test-
2868 // fixture navigation site in `mod tests` that probes the
2869 // rendered document at `.get(FLUX_HELMRELEASE_KEY_UPGRADE)`. Pin
2870 // the equality (and the static-data identity, peer with the
2871 // sibling
2872 // [`flux_helmrelease_key_install_re_export_points_at_caixa_core_canonical`]
2873 // pin on the peer install-path phase-discriminator half of the
2874 // same per-CR helm-action-phase discriminator parent-container-
2875 // axis-key pair) so any local re-introduction of a sibling
2876 // `pub const FLUX_HELMRELEASE_KEY_UPGRADE: &str = "…"` is a
2877 // build-time test failure naming the offending drift, not a
2878 // silent apply-time symptom (a stripped whole-upgrade-path per-
2879 // CR phase block letting the helm-controller fall back to the
2880 // Flux v2 upstream defaults for the whole upgrade-path phase
2881 // surface, silently dropping the substrate's
2882 // `remediateLastFailure: true` toggle + the per-CR retry-cap
2883 // ceiling from every per-version chart re-apply).
2884 caixa_core::assert_str_reexport_identity(
2885 "FLUX_HELMRELEASE_KEY_UPGRADE",
2886 FLUX_HELMRELEASE_KEY_UPGRADE,
2887 caixa_core::FLUX_HELMRELEASE_KEY_UPGRADE,
2888 );
2889 }
2890
2891 #[test]
2892 fn flux_helmrelease_key_upgrade_pins_canonical_upgrade_string() {
2893 // Bridge-arm pin: the lifted [`FLUX_HELMRELEASE_KEY_UPGRADE`]
2894 // constant resolves to the canonical `"upgrade"` string today,
2895 // and the rendered Flux v2 `HelmRelease` per-CR upgrade-path
2896 // phase sub-block-header must spell it out verbatim. Pin the
2897 // literal here (peer with the sibling
2898 // [`flux_helmrelease_key_install_pins_canonical_install_string`]-shape
2899 // canonical-default arm on the peer per-CR install-path phase-
2900 // discriminator surface) so a future rebrand of the lifted
2901 // constant (Flux v3 rename like `reapply` / `reconcile` /
2902 // `update` / `promote` — upstream Flux v3 roadmap candidates
2903 // that would land the same per-CR per-version chart re-apply
2904 // phase semantics under a different parent-container-axis-key)
2905 // surfaces here as a coordinated edit-point.
2906 assert_eq!(FLUX_HELMRELEASE_KEY_UPGRADE, "upgrade");
2907 }
2908
2909 #[test]
2910 fn flux_helmrelease_key_retries_pins_canonical_retries_string() {
2911 // Bridge-arm pin: the lifted [`FLUX_HELMRELEASE_KEY_RETRIES`]
2912 // constant resolves to the canonical `"retries"` string today,
2913 // and both rendered Flux v2 `HelmRelease` per-path retry-cap
2914 // leaf sub-block headers must spell it out verbatim. Pin the
2915 // literal here (peer with the sibling
2916 // [`flux_key_source_ref_pins_canonical_source_ref_string`]-shape
2917 // canonical-default arm on the sibling per-CR container-axis-key
2918 // surface) so a future rebrand of the lifted constant (Flux v3
2919 // rename like `attempts` / `maxRetries` / `retryCount` — the
2920 // upstream Gateway-API-side `spec.rules[].retry.attempts` leaf
2921 // already uses `attempts` on the sibling `GATEWAY_API_KEY_ATTEMPTS`
2922 // axis, an independent CRD group's evolution the two `pub const`
2923 // declarations stay sibling constants against) surfaces here as
2924 // a coordinated edit-point.
2925 assert_eq!(FLUX_HELMRELEASE_KEY_RETRIES, "retries");
2926 }
2927
2928 #[test]
2929 fn cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default() {
2930 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`
2931 // document's `spec.install.remediation.retries` scalar must
2932 // resolve to the lifted
2933 // [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] verbatim.
2934 // Before the lift the axis carried an inline `retries: 3`
2935 // scalar-value literal at the sole production-code call site
2936 // (the install-path `install.remediation.retries` position of
2937 // the [`cluster_bundle`] `helmrelease.yaml` format-string
2938 // template); a future substrate-side retry-ceiling migration on
2939 // the canonical
2940 // [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]
2941 // declaration that failed to reach this emit site would
2942 // silently split the substrate's canonical retry-ceiling
2943 // between the operator-facing canonical default and the per-
2944 // caixa `helmrelease.yaml` install-path retry cap the helm-
2945 // controller consumes at first-time chart apply time. Pin the
2946 // identity here so a regression that re-introduces an inline
2947 // literal at the emit site surfaces at build time on this
2948 // test's failure. Peer to the sibling
2949 // [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
2950 // pin on the upgrade-path retry-cap sibling axis — that test
2951 // pins the rendered upgrade-path scalar agrees with the lifted
2952 // default, this test pins the rendered install-path scalar
2953 // agrees with the same.
2954 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
2955 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
2956 let hr = files
2957 .iter()
2958 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
2959 .expect("helmrelease.yaml present");
2960 let parsed: serde_yaml::Value =
2961 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
2962 let install_retries = parsed
2963 .get(KUBE_KEY_SPEC)
2964 .and_then(|s| s.get(FLUX_HELMRELEASE_KEY_INSTALL))
2965 .and_then(|i| i.get(FLUX_HELMRELEASE_KEY_REMEDIATION))
2966 .and_then(|r| r.get(FLUX_HELMRELEASE_KEY_RETRIES))
2967 .and_then(|v| v.as_u64())
2968 .expect(
2969 "spec.install.remediation.retries scalar present; drift on \
2970 this axis silently splits the substrate's canonical retry-\
2971 ceiling between the install-path first-time chart apply and \
2972 the canonical `FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`",
2973 );
2974 assert_eq!(
2975 install_retries,
2976 u64::from(FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT),
2977 "spec.install.remediation.retries must carry the lifted \
2978 `FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT` scalar — \
2979 drift here silently splits the substrate's canonical retry-\
2980 ceiling between the operator-facing canonical default and \
2981 the install-path retry cap the Flux v2 helm-controller \
2982 consumes at first-time chart apply time"
2983 );
2984 }
2985
2986 #[test]
2987 fn cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default() {
2988 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`
2989 // document's `spec.upgrade.remediation.retries` scalar must
2990 // resolve to the lifted
2991 // [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] verbatim.
2992 // Before the lift the axis carried a second inline `retries: 3`
2993 // scalar-value literal at the sole production-code call site
2994 // (the upgrade-path `upgrade.remediation.retries` position of
2995 // the [`cluster_bundle`] `helmrelease.yaml` format-string
2996 // template, sibling to the install-path retry-cap the peer
2997 // [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
2998 // pin covers); a future substrate-side retry-ceiling migration
2999 // on the canonical
3000 // [`caixa_core::FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`]
3001 // declaration that failed to reach this emit site would
3002 // silently split the substrate's canonical retry-ceiling
3003 // between the operator-facing canonical default and the per-
3004 // caixa `helmrelease.yaml` upgrade-path retry cap the helm-
3005 // controller consumes on every subsequent per-version chart re-
3006 // apply the same `HelmRelease` CR gates. Pin the identity here
3007 // so a regression that re-introduces an inline literal at the
3008 // emit site surfaces at build time on this test's failure. Peer
3009 // to the sibling
3010 // [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
3011 // pin on the install-path retry-cap sibling axis — closing the
3012 // per-path retry-cap sweep the caixa-core lift established.
3013 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3014 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3015 let hr = files
3016 .iter()
3017 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
3018 .expect("helmrelease.yaml present");
3019 let parsed: serde_yaml::Value =
3020 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
3021 let upgrade_retries = parsed
3022 .get(KUBE_KEY_SPEC)
3023 .and_then(|s| s.get(FLUX_HELMRELEASE_KEY_UPGRADE))
3024 .and_then(|u| u.get(FLUX_HELMRELEASE_KEY_REMEDIATION))
3025 .and_then(|r| r.get(FLUX_HELMRELEASE_KEY_RETRIES))
3026 .and_then(|v| v.as_u64())
3027 .expect(
3028 "spec.upgrade.remediation.retries scalar present; drift on \
3029 this axis silently splits the substrate's canonical retry-\
3030 ceiling between the upgrade-path per-version chart re-apply \
3031 and the canonical `FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`",
3032 );
3033 assert_eq!(
3034 upgrade_retries,
3035 u64::from(FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT),
3036 "spec.upgrade.remediation.retries must carry the lifted \
3037 `FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT` scalar — \
3038 drift here silently splits the substrate's canonical retry-\
3039 ceiling between the operator-facing canonical default and \
3040 the upgrade-path retry cap the Flux v2 helm-controller \
3041 consumes on every subsequent per-caixa-version chart re-apply"
3042 );
3043 }
3044
3045 #[test]
3046 fn cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true() {
3047 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`
3048 // document's `spec.upgrade.remediation.remediateLastFailure`
3049 // upgrade-path-only per-CR remediation-toggle leaf-scalar-key must
3050 // resolve to `true` verbatim under the lifted
3051 // [`FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] leaf-key. Before
3052 // the lift the axis carried an inline `remediateLastFailure: true`
3053 // leaf-scalar-key literal at the sole production-code call site
3054 // (the upgrade-path `upgrade.remediation.remediateLastFailure`
3055 // position of the [`cluster_bundle`] `helmrelease.yaml` format-
3056 // string template, sibling to the upgrade-path retry-cap the peer
3057 // [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
3058 // pin covers); a future substrate-side rebrand on the canonical
3059 // [`caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`]
3060 // declaration that failed to reach this emit site would silently
3061 // strip the substrate's chosen post-retry-exhaustion rollback
3062 // semantic from every emitted per-caixa `HelmRelease` document —
3063 // the Flux v2 helm-controller would then leave every terminally-
3064 // failed upgrade in the failed state without rolling back to the
3065 // prior last-known-good release the substrate's "no chart apply
3066 // leaves a per-caixa CR in a stalled, unremediated state"
3067 // MESH-COMPOSITION.md §V guarantee mandates. Pin the identity
3068 // here so a regression that re-introduces an inline literal at
3069 // the emit site — or a rebrand on the canonical const that fails
3070 // to reach the emit site — surfaces at build time on this test's
3071 // failure. Peer to the sibling
3072 // [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
3073 // pin on the upgrade-path retry-cap sibling axis — closes the
3074 // `spec.upgrade.remediation.{retries, remediateLastFailure}` leaf-
3075 // scalar-key pair the substrate seeds under the upgrade-path per-
3076 // CR remediation sub-container.
3077 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3078 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3079 let hr = files
3080 .iter()
3081 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
3082 .expect("helmrelease.yaml present");
3083 let parsed: serde_yaml::Value =
3084 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
3085 let remediate_last_failure = parsed
3086 .get(KUBE_KEY_SPEC)
3087 .and_then(|s| s.get(FLUX_HELMRELEASE_KEY_UPGRADE))
3088 .and_then(|u| u.get(FLUX_HELMRELEASE_KEY_REMEDIATION))
3089 .and_then(|r| r.get(FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE))
3090 .and_then(|v| v.as_bool())
3091 .expect(
3092 "spec.upgrade.remediation.remediateLastFailure boolean scalar \
3093 present; drift on this axis silently drops the substrate's \
3094 chosen post-retry-exhaustion rollback semantic from every \
3095 emitted per-caixa `HelmRelease` document, leaving every \
3096 terminally-failed upgrade in the failed state without \
3097 rolling back to the prior last-known-good release",
3098 );
3099 assert_eq!(
3100 remediate_last_failure, FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT,
3101 "spec.upgrade.remediation.remediateLastFailure must carry the \
3102 lifted `FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT` \
3103 scalar — drift silently splits the substrate's canonical \
3104 post-retry-exhaustion rollback semantic between the operator-\
3105 facing canonical default and the per-caixa `HelmRelease` \
3106 document's per-CR upgrade-path remediation-toggle the Flux \
3107 v2 helm-controller's per-CR upgrade-path remediation loop \
3108 keys off to trigger the prior-release rollback pipeline once \
3109 the paired retry-cap ceiling has been exhausted, and every \
3110 terminally-failed per-caixa upgrade sits in the failed state \
3111 indefinitely with no diagnostic naming the remediation-\
3112 toggle-drift root cause"
3113 );
3114 }
3115
3116 #[test]
3117 fn flux_helmrelease_key_remediate_last_failure_re_export_points_at_caixa_core_canonical() {
3118 // The renderer's `FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE` was
3119 // lifted from the production-code inline `remediateLastFailure`
3120 // literal at the sole `cluster_bundle` `helmrelease.yaml` format-
3121 // string template's upgrade-path per-CR remediation-toggle leaf-
3122 // scalar-key emit site + the test-fixture navigation site the
3123 // sibling
3124 // [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
3125 // pin opens onto the rendered document, to a re-export of
3126 // [`caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE`] so
3127 // the canonical Flux v2 per-CR upgrade-path per-CR remediation-
3128 // toggle leaf-scalar-key lives in exactly one place across every
3129 // caixa renderer. Pin the equality + static-data identity here
3130 // so any local re-introduction of a sibling
3131 // `pub const FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE: &str = "…"`
3132 // at this crate (the canonical drift footgun where a sibling
3133 // local `pub const` could happen to carry the same string at the
3134 // source while pointing at a different `&'static` allocation) is
3135 // a build-time test failure naming the offending drift. Peer to
3136 // [`flux_helmrelease_key_retries_re_export_points_at_caixa_core_canonical`]
3137 // on the sibling per-CR retry-cap leaf-scalar-key re-export axis.
3138 caixa_core::assert_str_reexport_identity(
3139 "FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE",
3140 FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE,
3141 caixa_core::FLUX_HELMRELEASE_KEY_REMEDIATE_LAST_FAILURE,
3142 );
3143 }
3144
3145 #[test]
3146 fn flux_helmrelease_remediate_last_failure_default_re_export_matches_caixa_core_canonical_value()
3147 {
3148 // The renderer's `FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`
3149 // was lifted from the production-code inline `true` scalar-value
3150 // literal at the sole `cluster_bundle` `helmrelease.yaml` format-
3151 // string template's per-CR upgrade-path remediation-toggle scalar-
3152 // value emit site (the `remediateLastFailure: true` leaf inside
3153 // the per-CR `spec.upgrade.remediation` sub-block) + the test-
3154 // fixture navigation site the sibling
3155 // [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
3156 // pin's `assert!(remediate_last_failure)` predicate opened onto
3157 // the rendered document, to a re-export of
3158 // [`caixa_core::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT`]
3159 // so the canonical Flux v2 per-CR upgrade-path per-CR remediation-
3160 // toggle scalar-value default lives in exactly one place across
3161 // every caixa renderer. Pin the value-equality here so any local
3162 // re-introduction of a sibling
3163 // `pub const FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT: bool = …`
3164 // at this crate (the canonical drift footgun where a sibling
3165 // local `pub const` could happen to carry a drifted value) is a
3166 // build-time test failure naming the offending drift. Peer to
3167 // [`flux_helmrelease_key_remediate_last_failure_re_export_points_at_caixa_core_canonical`]
3168 // on the paired leaf-scalar-key half of the same `(key, value)`
3169 // per-CR `spec.upgrade.remediation.remediateLastFailure` pair —
3170 // the key half's re-export identity lives at the sibling
3171 // `assert_str_reexport_identity` pin, the value half's canonical
3172 // `bool` seed lives here. Same shape as the sibling
3173 // [`flux_kustomization_prune_default_re_export_matches_caixa_core_canonical_value`]
3174 // pin on the peer per-`Kustomization`-CR garbage-collection-
3175 // toggle scalar-value default axis.
3176 assert_eq!(
3177 FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT,
3178 caixa_core::FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT,
3179 "FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT re-export \
3180 must resolve to the canonical caixa_core value — drift \
3181 silently splits the substrate's canonical post-retry-\
3182 exhaustion rollback default between the two `pub const` \
3183 declarations, and every rendered per-caixa `helmrelease.yaml` \
3184 would emit a different per-CR upgrade-path remediation-toggle \
3185 scalar than every downstream consumer (the future M4 \
3186 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-\
3187 Aplicacao `HelmRelease` synthesis, the future admission-\
3188 webhook floor) reads at admit / reconcile time"
3189 );
3190 assert!(
3191 FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT,
3192 "FLUX_HELMRELEASE_REMEDIATE_LAST_FAILURE_DEFAULT must remain \
3193 `true` — the substrate's canonical \"no chart apply leaves \
3194 a per-caixa CR in a stalled, unremediated state\" \
3195 (MESH-COMPOSITION.md §V) guarantee requires every emitted \
3196 per-caixa `HelmRelease` opt into the helm-controller's per-CR \
3197 upgrade-path post-retry-exhaustion rollback pipeline; a drift \
3198 to `false` here silently leaves every terminally-failed \
3199 upgrade parked at `Ready: False` without rolling back to the \
3200 prior last-known-good release"
3201 );
3202 }
3203
3204 #[test]
3205 fn cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true() {
3206 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`
3207 // document's `spec.install.createNamespace` install-path-only
3208 // per-CR namespace-seeder-toggle leaf-scalar-key must resolve to
3209 // `true` verbatim under the lifted
3210 // [`FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] leaf-key. Before the
3211 // lift the axis carried an inline `createNamespace: true` leaf-
3212 // scalar-key literal at the sole production-code call site (the
3213 // install-path `install.createNamespace` position of the
3214 // [`cluster_bundle`] `helmrelease.yaml` format-string template,
3215 // mirror-symmetric to the upgrade-path remediation-toggle the peer
3216 // [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
3217 // pin covers); a future substrate-side rebrand on the canonical
3218 // [`caixa_core::FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`]
3219 // declaration that failed to reach this emit site would silently
3220 // strip the substrate's chosen first-apply namespace-seeder
3221 // semantic from every emitted per-caixa `HelmRelease` document —
3222 // the Flux v2 helm-controller would then refuse every first-time
3223 // per-caixa chart apply against a fresh cluster whose target
3224 // namespace has not been pre-provisioned by an out-of-band
3225 // pipeline the substrate's "no per-caixa Servico apply is blocked
3226 // on manual namespace preprovisioning" MESH-COMPOSITION.md §V
3227 // install-path-fluency guarantee mandates. Pin the identity here
3228 // so a regression that re-introduces an inline literal at the
3229 // emit site — or a rebrand on the canonical const that fails to
3230 // reach the emit site — surfaces at build time on this test's
3231 // failure. Peer to the sibling
3232 // [`cluster_bundle_helmrelease_upgrade_remediation_remediate_last_failure_pins_lifted_true`]
3233 // pin on the mirror-symmetric upgrade-path per-CR remediation-
3234 // toggle axis — closes the
3235 // `spec.{install.createNamespace, upgrade.remediation.remediateLastFailure}`
3236 // per-CR phase-specific toggle leaf-scalar-key pair the substrate
3237 // seeds under mirror-symmetric parent-container-axis-keys.
3238 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3239 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3240 let hr = files
3241 .iter()
3242 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
3243 .expect("helmrelease.yaml present");
3244 let parsed: serde_yaml::Value =
3245 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
3246 let create_namespace = parsed
3247 .get(KUBE_KEY_SPEC)
3248 .and_then(|s| s.get(FLUX_HELMRELEASE_KEY_INSTALL))
3249 .and_then(|i| i.get(FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE))
3250 .and_then(|v| v.as_bool())
3251 .expect(
3252 "spec.install.createNamespace boolean scalar present; drift \
3253 on this axis silently drops the substrate's chosen first-\
3254 apply namespace-seeder semantic from every emitted per-\
3255 caixa `HelmRelease` document, leaving every first-time \
3256 per-caixa chart apply against a fresh cluster refused by \
3257 the helm-controller because the target namespace was not \
3258 pre-provisioned by an out-of-band pipeline",
3259 );
3260 assert_eq!(
3261 create_namespace, FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT,
3262 "spec.install.createNamespace must carry the lifted \
3263 `FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT` scalar — drift \
3264 silently splits the substrate's canonical first-apply \
3265 namespace-seeder semantic between the operator-facing \
3266 canonical default and the per-caixa `HelmRelease` document's \
3267 per-CR install-path namespace-seeder-toggle the Flux v2 \
3268 helm-controller's per-CR install-path pre-apply loop keys \
3269 off to materialize the target namespace before the first \
3270 chart apply, and every first-time per-caixa Servico chart \
3271 apply against a fresh cluster is refused with no diagnostic \
3272 naming the seeder-toggle-drift root cause"
3273 );
3274 }
3275
3276 #[test]
3277 fn flux_helmrelease_key_create_namespace_re_export_points_at_caixa_core_canonical() {
3278 // The renderer's `FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE` was
3279 // lifted from the production-code inline `createNamespace`
3280 // literal at the sole `cluster_bundle` `helmrelease.yaml` format-
3281 // string template's install-path per-CR namespace-seeder-toggle
3282 // leaf-scalar-key emit site + the test-fixture navigation site
3283 // the sibling
3284 // [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
3285 // pin opens onto the rendered document, to a re-export of
3286 // [`caixa_core::FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE`] so the
3287 // canonical Flux v2 per-CR install-path per-CR namespace-seeder-
3288 // toggle leaf-scalar-key lives in exactly one place across every
3289 // caixa renderer. Pin the equality + static-data identity here so
3290 // any local re-introduction of a sibling
3291 // `pub const FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE: &str = "…"`
3292 // at this crate (the canonical drift footgun where a sibling
3293 // local `pub const` could happen to carry the same string at the
3294 // source while pointing at a different `&'static` allocation) is
3295 // a build-time test failure naming the offending drift. Peer to
3296 // [`flux_helmrelease_key_remediate_last_failure_re_export_points_at_caixa_core_canonical`]
3297 // on the sibling mirror-symmetric upgrade-path-only per-CR
3298 // remediation-toggle leaf-scalar-key re-export axis.
3299 caixa_core::assert_str_reexport_identity(
3300 "FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE",
3301 FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE,
3302 caixa_core::FLUX_HELMRELEASE_KEY_CREATE_NAMESPACE,
3303 );
3304 }
3305
3306 #[test]
3307 fn flux_helmrelease_create_namespace_default_re_export_matches_caixa_core_canonical_value() {
3308 // The renderer's `FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT` was
3309 // lifted from the production-code inline `true` scalar-value
3310 // literal at the sole `cluster_bundle` `helmrelease.yaml` format-
3311 // string template's per-CR install-path namespace-seeder-toggle
3312 // scalar-value emit site (the `createNamespace: true` leaf inside
3313 // the per-CR `spec.install` sub-block) + the test-fixture
3314 // navigation site the sibling
3315 // [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
3316 // pin's `assert!(create_namespace)` predicate opened onto the
3317 // rendered document, to a re-export of
3318 // [`caixa_core::FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT`] so
3319 // the canonical Flux v2 per-CR install-path per-CR namespace-
3320 // seeder-toggle scalar-value default lives in exactly one place
3321 // across every caixa renderer. Pin the value-equality here so any
3322 // local re-introduction of a sibling
3323 // `pub const FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT: bool = …`
3324 // at this crate (the canonical drift footgun where a sibling
3325 // local `pub const` could happen to carry a drifted value) is a
3326 // build-time test failure naming the offending drift. Peer to
3327 // [`flux_helmrelease_key_create_namespace_re_export_points_at_caixa_core_canonical`]
3328 // on the paired leaf-scalar-key half of the same `(key, value)`
3329 // per-CR `spec.install.createNamespace` pair — the key half's
3330 // re-export identity lives at the sibling
3331 // `assert_str_reexport_identity` pin, the value half's canonical
3332 // `bool` seed lives here. Same shape as the sibling
3333 // [`flux_helmrelease_remediate_last_failure_default_re_export_matches_caixa_core_canonical_value`]
3334 // pin on the peer mirror-symmetric upgrade-path-only per-CR
3335 // remediation-toggle scalar-value default axis.
3336 assert_eq!(
3337 FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT,
3338 caixa_core::FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT,
3339 "FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT re-export must \
3340 resolve to the canonical caixa_core value — drift silently \
3341 splits the substrate's canonical first-apply namespace-\
3342 seeder default between the two `pub const` declarations, \
3343 and every rendered per-caixa `helmrelease.yaml` would emit a \
3344 different per-CR install-path namespace-seeder-toggle scalar \
3345 than every downstream consumer (the future M4 \
3346 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-\
3347 Aplicacao `HelmRelease` synthesis, the future admission-\
3348 webhook floor) reads at admit / reconcile time"
3349 );
3350 assert!(
3351 FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT,
3352 "FLUX_HELMRELEASE_CREATE_NAMESPACE_DEFAULT must remain `true` \
3353 — the substrate's canonical \"no per-caixa Servico apply is \
3354 blocked on manual namespace preprovisioning\" \
3355 (MESH-COMPOSITION.md §V install-path-fluency) guarantee \
3356 requires every emitted per-caixa `HelmRelease` opt into the \
3357 helm-controller's per-CR install-path pre-apply namespace-\
3358 seeder pipeline; a drift to `false` here silently refuses \
3359 every first-time per-caixa chart apply against a fresh \
3360 cluster whose target namespace has not been pre-provisioned \
3361 by an out-of-band pipeline"
3362 );
3363 }
3364
3365 #[test]
3366 fn cluster_bundle_lareira_enabled_default_re_export_matches_caixa_core_canonical_value() {
3367 // The renderer's `CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT` was
3368 // lifted from the production-code inline `true` scalar-value
3369 // literal at the sole `cluster_bundle` `helmrelease.yaml` format-
3370 // string template's per-values-overlay child-chart-enablement-
3371 // toggle scalar-value emit site (the `enabled: true` leaf inside
3372 // the per-`{library_name}` values-overlay wrap under
3373 // `spec.values`) + the test-fixture navigation site the sibling
3374 // `cluster_bundle_helmrelease_wrap_key_pins_canonical_pleme_computeunit_string`
3375 // pin's `Some(true)` `.and_then(|v| v.as_bool())` predicate
3376 // opened onto the rendered document, to a re-export of
3377 // [`caixa_core::CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT`] so the
3378 // canonical substrate-side child-chart-enablement-toggle
3379 // scalar-value default lives in exactly one place across every
3380 // caixa renderer. Pin the value-equality here so any local
3381 // re-introduction of a sibling
3382 // `pub const CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT: bool = …`
3383 // at this crate (the canonical drift footgun where a sibling
3384 // local `pub const` could happen to carry a drifted value) is a
3385 // build-time test failure naming the offending drift. Peer to
3386 // `helm_values_key_enabled_re_export_points_at_caixa_core_canonical`
3387 // on the paired leaf-scalar-key half of the same
3388 // `(key, value)` per-values-overlay
3389 // `spec.values.<library>.enabled` pair — the key half's
3390 // re-export identity lives at the sibling
3391 // `assert_str_reexport_identity` pin, the value half's canonical
3392 // `bool` seed lives here. Same shape as the sibling
3393 // [`flux_helmrelease_create_namespace_default_re_export_matches_caixa_core_canonical_value`]
3394 // /
3395 // [`flux_helmrelease_remediate_last_failure_default_re_export_matches_caixa_core_canonical_value`]
3396 // /
3397 // [`flux_kustomization_prune_default_re_export_matches_caixa_core_canonical_value`]
3398 // pins on the peer canonical-Flux-v2-per-CR-substrate-default
3399 // re-export axes.
3400 assert_eq!(
3401 CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT,
3402 caixa_core::CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT,
3403 "CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT re-export must \
3404 resolve to the canonical caixa_core value — drift silently \
3405 splits the substrate's canonical force-on-under-composition \
3406 child-chart-enablement default between the two `pub const` \
3407 declarations, and every rendered per-caixa `helmrelease.yaml` \
3408 would emit a different per-values-overlay child-chart-\
3409 enablement toggle than every downstream consumer (the future \
3410 M4 `mesh.pleme.io/v1alpha1/Aplicacao` CR materializer's per-\
3411 Aplicacao `HelmRelease` synthesis) reads at admit / reconcile \
3412 time"
3413 );
3414 assert!(
3415 CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT,
3416 "CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT must remain `true` — \
3417 the `cluster_bundle` composition path is the substrate-side \
3418 opt-in path where the operator has already asserted per-caixa \
3419 cluster-scoped ownership by materializing a per-caixa \
3420 GitRepository + HelmRelease + Kustomization trio, so the \
3421 overlay must force the child chart on by seeding \
3422 `enabled: true` under the `values.<library>` wrap; a drift to \
3423 `false` here silently no-ops every per-caixa lareira child \
3424 chart at the per-cluster `HelmRelease` apply step, leaving \
3425 the paired standalone-chart-side `enabled: false` per-chart \
3426 default un-overridden"
3427 );
3428 }
3429
3430 #[test]
3431 fn cluster_bundle_kustomization_prune_pins_lifted_true() {
3432 // Fail-before-pass-after pin: the rendered `kustomization.yaml`
3433 // document's `spec.prune` per-CR garbage-collection-toggle leaf-
3434 // scalar-key must resolve to `true` verbatim under the lifted
3435 // [`FLUX_KUSTOMIZATION_KEY_PRUNE`] leaf-key. Before the lift the
3436 // axis carried an inline `prune: true` leaf-scalar-key literal
3437 // at the sole production-code call site (the top-level `spec`
3438 // position of the [`cluster_bundle`] `kustomization.yaml`
3439 // format-string template, mirror-symmetric to the per-caixa
3440 // `HelmRelease` CR install-path-only namespace-seeder-toggle the
3441 // peer
3442 // [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
3443 // pin covers on the co-resident per-caixa `HelmRelease` CR); a
3444 // future substrate-side rebrand on the canonical
3445 // [`caixa_core::FLUX_KUSTOMIZATION_KEY_PRUNE`] declaration that
3446 // failed to reach this emit site would silently strip the
3447 // substrate's chosen sweep-what-you-removed semantic from every
3448 // emitted per-caixa `Kustomization` document — the Flux v2
3449 // kustomize-controller would then leave every per-caixa
3450 // resource the source manifest set previously reconciled but no
3451 // longer carries dangling in the cluster the substrate's "the
3452 // cluster's per-caixa live state converges to the caixa's
3453 // tatara-lisp source-of-truth on every reconcile — resources
3454 // the source no longer carries are swept by the kustomize-
3455 // controller, not left dangling" CAIXA-SDLC.md §V author-to-
3456 // live-convergence guarantee mandates. Pin the identity here so
3457 // a regression that re-introduces an inline literal at the emit
3458 // site — or a rebrand on the canonical const that fails to
3459 // reach the emit site — surfaces at build time on this test's
3460 // failure. Peer to the sibling
3461 // [`cluster_bundle_helmrelease_install_create_namespace_pins_lifted_true`]
3462 // pin on the co-resident per-`HelmRelease`-CR install-path per-
3463 // CR namespace-seeder-toggle axis — extends the per-CR-toggle
3464 // leaf-scalar-key discipline from the co-resident per-
3465 // `HelmRelease`-CR spec surface onto the co-resident per-
3466 // `Kustomization`-CR spec surface at the mirror-symmetric top-
3467 // level `spec.prune` position.
3468 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3469 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3470 let ks = files
3471 .iter()
3472 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
3473 .expect("kustomization.yaml present");
3474 let parsed: serde_yaml::Value =
3475 serde_yaml::from_str(&ks.contents).expect("kustomization.yaml parses as YAML");
3476 let prune = parsed
3477 .get(KUBE_KEY_SPEC)
3478 .and_then(|s| s.get(FLUX_KUSTOMIZATION_KEY_PRUNE))
3479 .and_then(|v| v.as_bool())
3480 .expect(
3481 "spec.prune boolean scalar present; drift on this axis \
3482 silently drops the substrate's chosen sweep-what-you-\
3483 removed semantic from every emitted per-caixa \
3484 `Kustomization` document, leaving per-caixa resources \
3485 the source manifest set previously reconciled but no \
3486 longer carries dangling in the cluster",
3487 );
3488 assert_eq!(
3489 prune, FLUX_KUSTOMIZATION_PRUNE_DEFAULT,
3490 "spec.prune must carry the lifted \
3491 `FLUX_KUSTOMIZATION_PRUNE_DEFAULT` scalar — drift silently \
3492 splits the substrate's canonical sweep-what-you-removed \
3493 semantic between the operator-facing canonical default and \
3494 the per-caixa `Kustomization` document's per-CR garbage-\
3495 collection-toggle the Flux v2 kustomize-controller's per-CR \
3496 reconcile loop keys off to garbage-collect per-caixa resources \
3497 removed from the source manifest set between reconciles, and \
3498 every per-caixa `Kustomization` reconcile leaves orphaned \
3499 resources dangling in the cluster with no diagnostic naming \
3500 the toggle-drift root cause"
3501 );
3502 }
3503
3504 #[test]
3505 fn flux_kustomization_prune_default_re_export_matches_caixa_core_canonical_value() {
3506 // The renderer's `FLUX_KUSTOMIZATION_PRUNE_DEFAULT` was lifted
3507 // from the production-code inline `true` scalar-value literal at
3508 // the sole `cluster_bundle` `kustomization.yaml` format-string
3509 // template's per-CR garbage-collection-toggle scalar-value emit
3510 // site (the `prune: true` leaf inside the top-level `spec`
3511 // position) + the test-fixture navigation site the sibling
3512 // [`cluster_bundle_kustomization_prune_pins_lifted_true`] pin's
3513 // `assert!(prune)` predicate opened onto the rendered document,
3514 // to a re-export of [`caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT`]
3515 // so the canonical Flux v2 per-CR garbage-collection-toggle
3516 // scalar-value default lives in exactly one place across every
3517 // caixa renderer. Pin the value-equality here so any local re-
3518 // introduction of a sibling
3519 // `pub const FLUX_KUSTOMIZATION_PRUNE_DEFAULT: bool = …` at this
3520 // crate (the canonical drift footgun where a sibling local
3521 // `pub const` could happen to carry a drifted value) is a build-
3522 // time test failure naming the offending drift. Peer to
3523 // [`flux_kustomization_key_prune_re_export_points_at_caixa_core_canonical`]
3524 // on the paired leaf-scalar-key half of the same `(key, value)`
3525 // per-CR `spec.prune` pair — the key half's re-export identity
3526 // lives at the sibling `assert_str_reexport_identity` pin, the
3527 // value half's canonical `bool` seed lives here. Same shape as
3528 // the sibling
3529 // [`cluster_bundle_helmrelease_install_remediation_retries_pins_lifted_default`]
3530 // / [`cluster_bundle_helmrelease_upgrade_remediation_retries_pins_lifted_default`]
3531 // pins on the peer per-CR HelmRelease remediation retry-cap
3532 // scalar-value default axis — that default names the per-path
3533 // per-CR remediation retry ceiling, and this default names
3534 // whether the per-CR reconcile loop sweeps orphaned resources
3535 // at all.
3536 assert_eq!(
3537 FLUX_KUSTOMIZATION_PRUNE_DEFAULT,
3538 caixa_core::FLUX_KUSTOMIZATION_PRUNE_DEFAULT,
3539 "FLUX_KUSTOMIZATION_PRUNE_DEFAULT re-export must resolve to \
3540 the canonical caixa_core value — drift silently splits the \
3541 substrate's canonical sweep-what-you-removed default \
3542 between the two `pub const` declarations, and every rendered \
3543 per-caixa `kustomization.yaml` would emit a different \
3544 per-CR garbage-collection-toggle scalar than every downstream \
3545 consumer (the future M4 `mesh.pleme.io/v1alpha1/Aplicacao` \
3546 CR materializer's per-Aplicacao `Kustomization` synthesis, \
3547 the future admission-webhook floor) reads at admit / \
3548 reconcile time"
3549 );
3550 assert!(
3551 FLUX_KUSTOMIZATION_PRUNE_DEFAULT,
3552 "FLUX_KUSTOMIZATION_PRUNE_DEFAULT must remain `true` — the \
3553 substrate's canonical sweep-what-you-removed semantic \
3554 (CAIXA-SDLC.md §V author-to-live-convergence guarantee) \
3555 requires every emitted per-caixa `Kustomization` opt into \
3556 the kustomize-controller's per-CR resource-tracking \
3557 garbage-collection loop; a drift to `false` here silently \
3558 leaves orphaned resources dangling in every cluster the \
3559 substrate reconciles into"
3560 );
3561 }
3562
3563 #[test]
3564 fn flux_kustomization_key_prune_re_export_points_at_caixa_core_canonical() {
3565 // The renderer's `FLUX_KUSTOMIZATION_KEY_PRUNE` was lifted from
3566 // the production-code inline `prune` literal at the sole
3567 // `cluster_bundle` `kustomization.yaml` format-string template's
3568 // per-CR garbage-collection-toggle leaf-scalar-key emit site +
3569 // the test-fixture navigation site the sibling
3570 // [`cluster_bundle_kustomization_prune_pins_lifted_true`] pin
3571 // opens onto the rendered document, to a re-export of
3572 // [`caixa_core::FLUX_KUSTOMIZATION_KEY_PRUNE`] so the canonical
3573 // Flux v2 per-CR garbage-collection-toggle leaf-scalar-key lives
3574 // in exactly one place across every caixa renderer. Pin the
3575 // equality + static-data identity here so any local re-
3576 // introduction of a sibling
3577 // `pub const FLUX_KUSTOMIZATION_KEY_PRUNE: &str = "…"` at this
3578 // crate (the canonical drift footgun where a sibling local
3579 // `pub const` could happen to carry the same string at the
3580 // source while pointing at a different `&'static` allocation)
3581 // is a build-time test failure naming the offending drift. Peer
3582 // to
3583 // [`flux_helmrelease_key_create_namespace_re_export_points_at_caixa_core_canonical`]
3584 // on the sibling co-resident per-`HelmRelease`-CR install-path-
3585 // only per-CR namespace-seeder-toggle leaf-scalar-key re-export
3586 // axis.
3587 caixa_core::assert_str_reexport_identity(
3588 "FLUX_KUSTOMIZATION_KEY_PRUNE",
3589 FLUX_KUSTOMIZATION_KEY_PRUNE,
3590 caixa_core::FLUX_KUSTOMIZATION_KEY_PRUNE,
3591 );
3592 }
3593
3594 #[test]
3595 fn cluster_bundle_kustomization_path_pins_lifted_sub_tree() {
3596 // Fail-before-pass-after pin: the rendered `kustomization.yaml`
3597 // document's `spec.path` per-CR source-sub-tree leaf-scalar-key
3598 // must resolve to the canonical per-cluster / per-caixa sub-
3599 // tree path seed verbatim under the lifted
3600 // [`FLUX_KUSTOMIZATION_KEY_PATH`] leaf-key. Before the lift the
3601 // axis carried an inline `path: ./clusters/<cluster>/services/<name>`
3602 // leaf-scalar-key literal at the sole production-code call
3603 // site (the top-level `spec` position of the [`cluster_bundle`]
3604 // `kustomization.yaml` format-string template, mirror-symmetric
3605 // to the co-resident per-`Kustomization`-CR garbage-collection-
3606 // toggle the sibling
3607 // [`cluster_bundle_kustomization_prune_pins_lifted_true`] pin
3608 // covers). A future substrate-side rebrand on the canonical
3609 // [`caixa_core::FLUX_KUSTOMIZATION_KEY_PATH`] declaration that
3610 // failed to reach this emit site would silently unbind every
3611 // emitted per-caixa `Kustomization` from its paired per-caixa
3612 // sub-tree of the pleme-io k8s repository — the Flux v2
3613 // kustomize-controller would then either reconcile the whole
3614 // GitRepository root (when the CR omits the leaf, the
3615 // controller defaults to `./`, pulling every unrelated cluster's
3616 // manifests through the wrong per-caixa `Kustomization`) or
3617 // refuse to reconcile at all (when the leaf points at a path
3618 // the GitRepository doesn't carry, the CR sits perpetually at
3619 // `BuildFailed`). Pin the identity here so a regression that
3620 // re-introduces an inline literal at the emit site — or a
3621 // rebrand on the canonical const that fails to reach the emit
3622 // site — surfaces at build time on this test's failure. Peer
3623 // to the sibling
3624 // [`cluster_bundle_kustomization_prune_pins_lifted_true`] pin
3625 // on the co-resident per-`Kustomization`-CR garbage-collection-
3626 // toggle axis — extends the per-`Kustomization`-CR-spec leaf-
3627 // scalar-key discipline from the co-resident garbage-
3628 // collection-toggle onto the co-resident source-sub-tree
3629 // pointer at the mirror-symmetric top-level `spec.path`
3630 // position.
3631 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3632 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3633 let ks = files
3634 .iter()
3635 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
3636 .expect("kustomization.yaml present");
3637 let parsed: serde_yaml::Value =
3638 serde_yaml::from_str(&ks.contents).expect("kustomization.yaml parses as YAML");
3639 let path = parsed
3640 .get(KUBE_KEY_SPEC)
3641 .and_then(|s| s.get(FLUX_KUSTOMIZATION_KEY_PATH))
3642 .and_then(|v| v.as_str())
3643 .expect(
3644 "spec.path string scalar present; drift on this axis \
3645 silently unbinds every per-caixa Kustomization from \
3646 its paired per-caixa sub-tree of the pleme-io k8s \
3647 repository, and the kustomize-controller either \
3648 defaults to reconciling the GitRepository root or \
3649 refuses to reconcile at all",
3650 );
3651 // Route the per-caixa `:nome` axis-projection through the
3652 // substrate-canonical [`Caixa::nome`] `&str`-return accessor
3653 // rather than the raw `&sample_caixa().nome` `&String`-borrow
3654 // of the underlying field, so a future rebrand of the
3655 // top-level [`Caixa`] `:nome` universal-axis storage (a
3656 // pre-parsed `CaixaName`-newtype cache the accessor could
3657 // materialize behind the same `&str` return contract, a
3658 // per-cluster `:placement`-scoped nome overlay the caixa-
3659 // operator reconciles ahead of dispatch) reaches this
3660 // fixture-navigation site through the one accessor edit at
3661 // the canonical `caixa-core` declaration rather than a
3662 // coordinated rewrite that includes this file too. Peer to
3663 // the sibling
3664 // [`cluster_bundle_kustomization_spec_path_uses_lifted_composer`]
3665 // pin below on the paired composer-equivalence test-fixture
3666 // navigation site — both halves of the `sample_caixa()`
3667 // per-`:nome` fixture-navigation axis now route through the
3668 // one typed dispatch on the substrate primitive.
3669 let expected = flux_kustomization_source_subtree(&opts.cluster, sample_caixa().nome());
3670 assert_eq!(
3671 path, expected,
3672 "spec.path must carry the substrate's canonical per-cluster \
3673 / per-caixa sub-tree seed — drift silently unbinds every \
3674 per-caixa Kustomization from its paired sub-tree of the \
3675 pleme-io k8s repository"
3676 );
3677 }
3678
3679 #[test]
3680 fn flux_kustomization_key_path_re_export_points_at_caixa_core_canonical() {
3681 // The renderer's `FLUX_KUSTOMIZATION_KEY_PATH` was lifted from
3682 // the production-code inline `path` literal at the sole
3683 // `cluster_bundle` `kustomization.yaml` format-string template's
3684 // per-CR source-sub-tree leaf-scalar-key emit site + the test-
3685 // fixture navigation site the sibling
3686 // [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`] pin
3687 // opens onto the rendered document, to a re-export of
3688 // [`caixa_core::FLUX_KUSTOMIZATION_KEY_PATH`] so the canonical
3689 // Flux v2 per-CR source-sub-tree leaf-scalar-key lives in
3690 // exactly one place across every caixa renderer. Pin the
3691 // equality + static-data identity here so any local re-
3692 // introduction of a sibling
3693 // `pub const FLUX_KUSTOMIZATION_KEY_PATH: &str = "…"` at this
3694 // crate (the canonical drift footgun where a sibling local
3695 // `pub const` could happen to carry the same string at the
3696 // source while pointing at a different `&'static` allocation)
3697 // is a build-time test failure naming the offending drift.
3698 // Peer to
3699 // [`flux_kustomization_key_prune_re_export_points_at_caixa_core_canonical`]
3700 // on the sibling co-resident per-`Kustomization`-CR garbage-
3701 // collection-toggle leaf-scalar-key re-export axis.
3702 caixa_core::assert_str_reexport_identity(
3703 "FLUX_KUSTOMIZATION_KEY_PATH",
3704 FLUX_KUSTOMIZATION_KEY_PATH,
3705 caixa_core::FLUX_KUSTOMIZATION_KEY_PATH,
3706 );
3707 }
3708
3709 #[test]
3710 fn flux_kustomization_source_subtree_re_export_matches_caixa_core_canonical_output() {
3711 // The renderer's `flux_kustomization_source_subtree` was lifted
3712 // from the verbatim inline
3713 // `format!("./clusters/{cluster}/services/{name}")` at the sole
3714 // `cluster_bundle` `kustomization.yaml` format-string production
3715 // emit site + a mirror-symmetric verbatim inline
3716 // `format!("./clusters/{cluster}/services/{name}", …)` at the
3717 // paired `cluster_bundle_kustomization_path_pins_lifted_sub_tree`
3718 // test-fixture navigation site, to a re-export of
3719 // [`caixa_core::flux_kustomization_source_subtree`]. Pin the
3720 // output-shape equality here on representative fixtures so any
3721 // local re-introduction of a sibling
3722 // `pub fn flux_kustomization_source_subtree(...)` shadow at this
3723 // crate (the canonical drift footgun where a sibling local
3724 // `pub fn` could happen to produce the same byte-shape at the
3725 // source while diverging on either axis of the composition) is
3726 // a build-time test failure naming the offending drift. Peer to
3727 // [`flux_kustomization_key_path_re_export_points_at_caixa_core_canonical`]
3728 // on the paired leaf-scalar-key half of the same `(key, value)`
3729 // per-CR `spec.path` pair — the key half's re-export identity
3730 // lives at the sibling `assert_str_reexport_identity` pin, the
3731 // value half's canonical composition lives here. Same shape as
3732 // the sibling composer re-export identity pins the
3733 // [`caixa_mesh::cilium_network_policy_name`] and
3734 // [`caixa_mesh::gateway_api_http_route_name`] re-exports carry
3735 // at their crate's `mod tests` — every composer re-export in
3736 // the substrate reaches the canonical `caixa-core` function
3737 // through one `pub use` and the test-side output-shape identity
3738 // pin closes the "sibling `pub fn` shadow" footgun by
3739 // construction.
3740 assert_eq!(
3741 flux_kustomization_source_subtree("rio", "hello-rio"),
3742 caixa_core::flux_kustomization_source_subtree("rio", "hello-rio"),
3743 );
3744 assert_eq!(
3745 flux_kustomization_source_subtree("rio", "hello-rio"),
3746 "./clusters/rio/services/hello-rio",
3747 );
3748 assert_eq!(
3749 flux_kustomization_source_subtree("paris", "cart"),
3750 caixa_core::flux_kustomization_source_subtree("paris", "cart"),
3751 );
3752 }
3753
3754 #[test]
3755 fn cluster_bundle_kustomization_spec_path_uses_lifted_composer() {
3756 // Composition pin: the `spec.path` scalar emitted by
3757 // `cluster_bundle` for every per-caixa `kustomization.yaml`
3758 // document must byte-equal the output of the lifted
3759 // [`flux_kustomization_source_subtree`] composer with the same
3760 // `(cluster, nome)` arguments — so a future refactor of the
3761 // composer's internals (per-cluster prefix rebrand, per-caixa
3762 // infix rebrand, multi-tenant scoping prefix) reaches the
3763 // renderer through the one function-pointer edit at the
3764 // canonical `caixa-core` declaration, and any rewrite of the
3765 // format-string template's `{path_key}: {source_subtree}` emit
3766 // site that desynchronizes from the composer fires here at
3767 // build-time rather than silently splitting the writer-side
3768 // sub-tree seed at emit time. Peer to
3769 // [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`]
3770 // above on the paired output-shape assertion — that pin locks
3771 // the emitted `spec.path` scalar against the composer's output;
3772 // this pin locks the equivalence to the composer with the
3773 // ClusterBundleOpts's `cluster` axis threaded through, so a
3774 // regression that pinned one axis at the emit site while
3775 // leaving the peer axis inline surfaces on either half.
3776 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3777 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3778 let ks = files
3779 .iter()
3780 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
3781 .expect("kustomization.yaml present");
3782 let parsed: serde_yaml::Value =
3783 serde_yaml::from_str(&ks.contents).expect("kustomization.yaml parses as YAML");
3784 let emitted = parsed
3785 .get(KUBE_KEY_SPEC)
3786 .and_then(|s| s.get(FLUX_KUSTOMIZATION_KEY_PATH))
3787 .and_then(|v| v.as_str())
3788 .expect("spec.path string scalar present")
3789 .to_owned();
3790 // Route the per-caixa `:nome` axis-projection through the
3791 // substrate-canonical [`Caixa::nome`] `&str`-return accessor
3792 // rather than the raw `&sample_caixa().nome` `&String`-borrow
3793 // of the underlying field — sibling to the peer
3794 // [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`]
3795 // pin's own accessor route at the paired output-shape
3796 // assertion site. Closes the last pair of unlifted raw
3797 // `sample_caixa().nome` field-access sites in the caixa-flux
3798 // test suite; the twin `(cluster, nome)`-argument-pair
3799 // `flux_kustomization_source_subtree` fixture-navigation half
3800 // of the per-caixa `:nome` axis now uniformly routes through
3801 // the substrate primitive.
3802 let composed = flux_kustomization_source_subtree(&opts.cluster, sample_caixa().nome());
3803 assert_eq!(
3804 emitted, composed,
3805 "spec.path emit must byte-equal the lifted \
3806 flux_kustomization_source_subtree composer's output — drift \
3807 at either half silently splits the per-cluster / per-caixa \
3808 sub-tree seed axis at emit time from the canonical composer"
3809 );
3810 }
3811
3812 #[test]
3813 fn sample_caixa_nome_accessor_byte_equals_raw_field() {
3814 // Byte-parity pin: [`Caixa::nome`]'s `&str`-return accessor
3815 // must project the same bytes as the raw `sample_caixa().nome`
3816 // `String`-field access on the shared per-test [`sample_caixa`]
3817 // fixture the caixa-flux test-suite's per-`cluster_bundle`
3818 // `spec.path` composer-equivalence pins
3819 // ([`cluster_bundle_kustomization_path_pins_lifted_sub_tree`],
3820 // [`cluster_bundle_kustomization_spec_path_uses_lifted_composer`])
3821 // navigate through. Guards the paired-site convergence that
3822 // just routed both fixture-navigation halves through the
3823 // accessor rather than the raw field: a future implementation
3824 // of [`Caixa::nome`] that returned a differently-bytewidth
3825 // projection (a cached `CaixaName` newtype's `Display` value,
3826 // an operator-side normalized ASCII-lowered projection) would
3827 // silently split the composer's fixture-navigation input from
3828 // the storage-side field the [`crate::cluster_bundle`]
3829 // production emit path still reads from at the peer
3830 // `format!(…, name = &caixa.nome, …)` production site (which
3831 // itself already reaches through [`Caixa::nome`]'s accessor
3832 // — see caixa-flux/src/lib.rs:2135) — this pin surfaces the
3833 // drift at build-time rather than at a downstream
3834 // `kubectl get kustomization` audit on the fleet.
3835 //
3836 // Same byte-parity-pin discipline the sibling caixa-crd
3837 // `round_trip_preserves_core_fields` test-side accessor
3838 // convergence (1a160cd) added to lock its own per-`Caixa`
3839 // scalar-accessor family against the raw field-access at the
3840 // paired serde round-trip fixture — extended here onto the
3841 // caixa-flux `sample_caixa()` fixture's per-`:nome`
3842 // scalar-accessor axis.
3843 let fixture = sample_caixa();
3844 assert_eq!(
3845 fixture.nome(),
3846 fixture.nome.as_str(),
3847 "Caixa::nome() must borrow the same bytes as the raw \
3848 `nome: String` field storage; any implementation drift \
3849 here silently splits every caixa-flux composer-fixture \
3850 navigation site that routes through the accessor from \
3851 the storage-side field the peer production emit path \
3852 still reads verbatim"
3853 );
3854 }
3855
3856 #[test]
3857 fn cluster_bundle_kustomization_timeout_pins_lifted_default() {
3858 // Fail-before-pass-after pin: the rendered `kustomization.yaml`
3859 // document's `spec.timeout` per-CR reconcile wall-clock cap
3860 // leaf-scalar-key must resolve to the canonical
3861 // [`DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] scalar-value verbatim
3862 // under the lifted [`FLUX_KUSTOMIZATION_KEY_TIMEOUT`] leaf-key.
3863 // Before the lift the axis carried an inline `timeout: 5m` leaf-
3864 // scalar literal at the sole production-code call site (the
3865 // top-level `spec` position of the [`cluster_bundle`]
3866 // `kustomization.yaml` format-string template, sibling to the
3867 // co-resident per-`Kustomization`-CR source-sub-tree pointer
3868 // the peer [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`]
3869 // pin covers). A future substrate-side rebrand on either half
3870 // of the canonical `(FLUX_KUSTOMIZATION_KEY_TIMEOUT,
3871 // DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT)` pair that failed to
3872 // reach this emit site would silently strip the substrate's
3873 // chosen reconcile-ceiling declaration from every emitted per-
3874 // caixa `Kustomization` document — the Flux v2 kustomize-
3875 // controller would then fall back to the upstream Flux v2
3876 // controller-side default cap (which the upstream project
3877 // ships tuned for the average upstream Flux-managed manifest
3878 // set, not the substrate's per-caixa idempotency-checkpoint
3879 // cadence the peer
3880 // [`FLUX_HELMRELEASE_REMEDIATION_RETRIES_DEFAULT`] retry-
3881 // ceiling and [`DEFAULT_FLUX_RECONCILE_INTERVAL`] reconcile-
3882 // poll cadence are jointly tuned against), letting a
3883 // persistently-failing per-caixa manifest apply consume
3884 // kustomize-controller reconcile-loop cycles past the
3885 // substrate's chosen ceiling with no field naming the timeout-
3886 // drift root cause. Pin the identity here so a regression that
3887 // re-introduces an inline literal at the emit site — or a
3888 // rebrand on either canonical const that fails to reach the
3889 // emit site — surfaces at build time on this test's failure.
3890 // Peer to the sibling
3891 // [`cluster_bundle_kustomization_path_pins_lifted_sub_tree`]
3892 // and [`cluster_bundle_kustomization_prune_pins_lifted_true`]
3893 // pins on the co-resident per-`Kustomization`-CR spec surface
3894 // axes — extends the per-`Kustomization`-CR-spec leaf-scalar-
3895 // key/scalar-value discipline from the co-resident source-
3896 // sub-tree pointer and garbage-collection-toggle onto the co-
3897 // resident reconcile wall-clock cap at the mirror-symmetric
3898 // top-level `spec.timeout` position.
3899 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
3900 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
3901 let ks = files
3902 .iter()
3903 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
3904 .expect("kustomization.yaml present");
3905 let parsed: serde_yaml::Value =
3906 serde_yaml::from_str(&ks.contents).expect("kustomization.yaml parses as YAML");
3907 let timeout = parsed
3908 .get(KUBE_KEY_SPEC)
3909 .and_then(|s| s.get(FLUX_KUSTOMIZATION_KEY_TIMEOUT))
3910 .and_then(|v| v.as_str())
3911 .expect(
3912 "spec.timeout string scalar present; drift on this axis \
3913 silently strips the substrate's chosen reconcile-ceiling \
3914 declaration from every emitted per-caixa `Kustomization` \
3915 document, letting the kustomize-controller fall back to \
3916 the upstream Flux v2 controller-side default cap",
3917 );
3918 assert_eq!(
3919 timeout, DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT,
3920 "spec.timeout must carry the substrate's canonical Flux v2 \
3921 per-`Kustomization`-CR reconcile wall-clock cap seed — drift \
3922 silently strips the substrate's chosen reconcile-ceiling \
3923 declaration from every emitted per-caixa `Kustomization` \
3924 document"
3925 );
3926 }
3927
3928 #[test]
3929 fn flux_kustomization_key_timeout_re_export_points_at_caixa_core_canonical() {
3930 // The renderer's `FLUX_KUSTOMIZATION_KEY_TIMEOUT` was lifted
3931 // from the production-code inline `timeout` literal at the
3932 // sole `cluster_bundle` `kustomization.yaml` format-string
3933 // template's per-CR reconcile wall-clock cap leaf-scalar-key
3934 // emit site + the test-fixture navigation site the sibling
3935 // [`cluster_bundle_kustomization_timeout_pins_lifted_default`]
3936 // pin opens onto the rendered document, to a re-export of
3937 // [`caixa_core::FLUX_KUSTOMIZATION_KEY_TIMEOUT`] so the
3938 // canonical Flux v2 per-CR reconcile wall-clock cap leaf-
3939 // scalar-key lives in exactly one place across every caixa
3940 // renderer. Pin the equality + static-data identity here so
3941 // any local re-introduction of a sibling
3942 // `pub const FLUX_KUSTOMIZATION_KEY_TIMEOUT: &str = "…"` at
3943 // this crate (the canonical drift footgun where a sibling
3944 // local `pub const` could happen to carry the same string at
3945 // the source while pointing at a different `&'static`
3946 // allocation) is a build-time test failure naming the
3947 // offending drift. Peer to
3948 // [`flux_kustomization_key_path_re_export_points_at_caixa_core_canonical`]
3949 // and
3950 // [`flux_kustomization_key_prune_re_export_points_at_caixa_core_canonical`]
3951 // on the sibling co-resident per-`Kustomization`-CR spec
3952 // surface re-export axes.
3953 caixa_core::assert_str_reexport_identity(
3954 "FLUX_KUSTOMIZATION_KEY_TIMEOUT",
3955 FLUX_KUSTOMIZATION_KEY_TIMEOUT,
3956 caixa_core::FLUX_KUSTOMIZATION_KEY_TIMEOUT,
3957 );
3958 }
3959
3960 #[test]
3961 fn default_flux_kustomization_timeout_re_export_points_at_caixa_core_canonical() {
3962 // The renderer's `DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT` was
3963 // lifted from the production-code inline `5m` scalar-value
3964 // literal at the sole `cluster_bundle` `kustomization.yaml`
3965 // format-string template's per-CR reconcile wall-clock cap
3966 // emit site, to a re-export of
3967 // [`caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT`] so the
3968 // canonical Flux v2 per-CR reconcile wall-clock cap default
3969 // scalar-value lives in exactly one place across every caixa
3970 // renderer. Pin the equality + static-data identity here so
3971 // any local re-introduction of a sibling
3972 // `pub const DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT: &str = "…"`
3973 // at this crate (the canonical drift footgun where a sibling
3974 // local `pub const` could happen to carry the same string at
3975 // the source while pointing at a different `&'static`
3976 // allocation) is a build-time test failure naming the
3977 // offending drift. Peer to
3978 // [`default_flux_reconcile_interval_re_export_points_at_caixa_core_canonical`]
3979 // on the sibling canonical-Flux-v2-per-CR-substrate-default-
3980 // scalar re-export axis.
3981 caixa_core::assert_str_reexport_identity(
3982 "DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT",
3983 DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT,
3984 caixa_core::DEFAULT_FLUX_KUSTOMIZATION_TIMEOUT,
3985 );
3986 }
3987
3988 #[test]
3989 fn kube_key_spec_re_export_points_at_caixa_core_canonical() {
3990 // The renderer's `KUBE_KEY_SPEC` was lifted from the
3991 // production-code inline `"spec"` literals at the two K8s-CR
3992 // top-level-spec-axis call sites (`programs_yaml_entry`'s
3993 // `computeunit_yaml.get("spec")` ComputeUnit-side spec read +
3994 // its matching `Error::MissingField("spec")` diagnostic;
3995 // `upsert_into_helmrelease_programs`'s `root.get_mut("spec")`
3996 // HelmRelease-side spec mutate + its matching
3997 // `Error::MissingField("spec")` diagnostic) to a re-export of
3998 // [`caixa_core::KUBE_KEY_SPEC`] so the canonical K8s-CR
3999 // top-level spec-axis string lives in exactly one place across
4000 // every caixa renderer. Pin the equality + static-data
4001 // identity here so any local re-introduction of a sibling
4002 // `pub const KUBE_KEY_SPEC: &str = "…"` (the canonical drift
4003 // footgun where a sibling local `pub const` could happen to
4004 // carry the same string at the source while pointing at a
4005 // different `&'static` allocation) is a build-time test
4006 // failure naming the offending drift. Peer to
4007 // [`default_namespace_re_export_points_at_caixa_core_canonical`]
4008 // on the sibling re-export axis +
4009 // `caixa_mesh::tests::kube_key_spec_re_export_points_at_caixa_core_canonical`
4010 // on the sibling renderer crate.
4011 caixa_core::assert_str_reexport_identity(
4012 "KUBE_KEY_SPEC",
4013 KUBE_KEY_SPEC,
4014 caixa_core::KUBE_KEY_SPEC,
4015 );
4016 }
4017
4018 #[test]
4019 fn kube_key_metadata_re_export_points_at_caixa_core_canonical() {
4020 // The renderer's `KUBE_KEY_METADATA` was lifted from the
4021 // production-code inline `"metadata"` literal at
4022 // `programs_yaml_entry`'s `computeunit_yaml.get("metadata")`
4023 // ComputeUnit-side metadata read + the drift-detection pin at
4024 // `cluster_bundle_kustomization_carries_flux_system_namespace_axes`'s
4025 // `parsed.get("metadata")` rendered-kustomization traversal, to a
4026 // re-export of [`caixa_core::KUBE_KEY_METADATA`] so the canonical
4027 // K8s-CR top-level metadata-axis string lives in exactly one
4028 // place across every caixa renderer. Pin the equality +
4029 // static-data identity here so any local re-introduction of a
4030 // sibling `pub const KUBE_KEY_METADATA: &str = "…"` (the
4031 // canonical drift footgun where a sibling local `pub const`
4032 // could happen to carry the same string at the source while
4033 // pointing at a different `&'static` allocation) is a build-time
4034 // test failure naming the offending drift. Peer to
4035 // [`kube_key_spec_re_export_points_at_caixa_core_canonical`] on
4036 // the sibling K8s-CR top-level-spec-axis re-export +
4037 // `caixa_mesh::tests::kube_key_metadata_re_export_points_at_caixa_core_canonical`
4038 // on the sibling renderer crate.
4039 caixa_core::assert_str_reexport_identity(
4040 "KUBE_KEY_METADATA",
4041 KUBE_KEY_METADATA,
4042 caixa_core::KUBE_KEY_METADATA,
4043 );
4044 }
4045
4046 #[test]
4047 fn kube_key_kind_re_export_points_at_caixa_core_canonical() {
4048 // The renderer's `KUBE_KEY_KIND` was lifted from eleven inline
4049 // `"kind"` literals at the test-side K8s-CR top-level-kind-axis
4050 // retrieval calls that navigate the rendered `cluster_bundle`
4051 // multi-file sequence to isolate each per-`(GitRepository,
4052 // HelmRelease, Kustomization)` document's top-level-kind
4053 // discriminator plus its nested `spec.chart.spec.sourceRef.kind`
4054 // (helmrelease) / `spec.sourceRef.kind` (kustomization) /
4055 // `spec.healthChecks[].kind` (kustomization) drift-detection
4056 // pins, to a re-export of [`caixa_core::KUBE_KEY_KIND`] so the
4057 // canonical K8s-CR top-level kind-discriminator axis string
4058 // lives in exactly one place across every caixa renderer. Pin
4059 // the equality + static-data identity here so any local
4060 // re-introduction of a sibling `pub const KUBE_KEY_KIND: &str
4061 // = "…"` (the canonical drift footgun where a sibling local
4062 // `pub const` could happen to carry the same string at the
4063 // source while pointing at a different `&'static` allocation)
4064 // is a build-time test failure naming the offending drift, not
4065 // a silent apply-time symptom — the prior shape would have let
4066 // a typo on any one sibling `pub const` declaration silently
4067 // miss the per-CR kind retrieval so the drift-detection
4068 // `.get(KUBE_KEY_KIND).and_then(|n| n.as_str()) == Some(…)`
4069 // predicate the sibling `FLUX_KIND_*` re-export pins rest on
4070 // would compare against `None` under the trailing
4071 // `.expect("… present")` panic and mask the true sibling
4072 // `FLUX_KIND_*` axis drift. Peer to
4073 // [`kube_key_spec_re_export_points_at_caixa_core_canonical`] +
4074 // [`kube_key_metadata_re_export_points_at_caixa_core_canonical`]
4075 // on the sibling K8s-CR top-level-spec / top-level-metadata
4076 // axis re-exports + `caixa_mesh::tests::kube_key_kind_re_export_points_at_caixa_core_canonical`
4077 // (615a13d) on the sibling renderer crate — completes the
4078 // per-K8s-CR top-level `(spec, metadata, kind)` axis re-export
4079 // triple every rendered Flux bundle document navigates.
4080 caixa_core::assert_str_reexport_identity(
4081 "KUBE_KEY_KIND",
4082 KUBE_KEY_KIND,
4083 caixa_core::KUBE_KEY_KIND,
4084 );
4085 }
4086
4087 #[test]
4088 fn kube_key_api_version_re_export_points_at_caixa_core_canonical() {
4089 // The renderer's `KUBE_KEY_API_VERSION` was lifted from four
4090 // inline `"apiVersion"` literals at the test-side K8s-CR
4091 // top-level-apiVersion-axis retrieval calls that navigate the
4092 // rendered `cluster_bundle` multi-file sequence to isolate each
4093 // per-`(GitRepository, HelmRelease, Kustomization)` document's
4094 // top-level-apiVersion axis plus the `kustomization.yaml`'s
4095 // nested `spec.healthChecks[].apiVersion` drift-detection pin,
4096 // to a re-export of [`caixa_core::KUBE_KEY_API_VERSION`] so the
4097 // canonical K8s-CR top-level apiVersion-axis string lives in
4098 // exactly one place across every caixa renderer. Pin the
4099 // equality + static-data identity here so any local
4100 // re-introduction of a sibling `pub const KUBE_KEY_API_VERSION:
4101 // &str = "…"` (the canonical drift footgun where a sibling
4102 // local `pub const` could happen to carry the same string at
4103 // the source while pointing at a different `&'static`
4104 // allocation) is a build-time test failure naming the offending
4105 // drift, not a silent apply-time symptom — the prior shape
4106 // would have let a typo on any one sibling `pub const`
4107 // declaration silently miss the per-CR apiVersion retrieval so
4108 // the drift-detection `.get(KUBE_KEY_API_VERSION).and_then(|n|
4109 // n.as_str()) == Some(…)` predicate the sibling
4110 // `FLUX_*_API_VERSION` re-export pins rest on would compare
4111 // against `None` under the trailing `.expect("… present")`
4112 // panic and mask the true sibling `FLUX_*_API_VERSION` axis
4113 // drift. Peer to
4114 // [`kube_key_spec_re_export_points_at_caixa_core_canonical`] +
4115 // [`kube_key_metadata_re_export_points_at_caixa_core_canonical`]
4116 // + [`kube_key_kind_re_export_points_at_caixa_core_canonical`]
4117 // on the sibling K8s-CR top-level-spec / top-level-metadata /
4118 // top-level-kind axis re-exports — completes the per-K8s-CR
4119 // top-level `(apiVersion, kind, metadata, spec)` axis
4120 // re-export quartet every rendered Flux v2 bundle document
4121 // navigates.
4122 caixa_core::assert_str_reexport_identity(
4123 "KUBE_KEY_API_VERSION",
4124 KUBE_KEY_API_VERSION,
4125 caixa_core::KUBE_KEY_API_VERSION,
4126 );
4127 }
4128
4129 #[test]
4130 fn kube_key_namespace_re_export_points_at_caixa_core_canonical() {
4131 // The renderer's `KUBE_KEY_NAMESPACE` was lifted from five inline
4132 // `"namespace"` literals — the two production-code call sites in
4133 // `programs_yaml_entry` (the ComputeUnit YAML's
4134 // `metadata.namespace` retrieval that feeds the emitted
4135 // `programs:[]` entry's isomorphic `namespace:` field, and the
4136 // write-side entry-key emission the `lareira-fleet-programs`
4137 // schema keys the per-Servico namespace off) plus the three
4138 // test-side drift-detection call sites (the two
4139 // `programs_yaml_entry` round-trip pins asserting the emitted
4140 // entry's `namespace:` field spells `tatara-system` on the
4141 // metadata-carried path and [`DEFAULT_NAMESPACE`] on the
4142 // fallback path, and the `cluster_bundle_kustomization_carries_\
4143 // flux_system_namespace_axes` pin asserting the rendered
4144 // `kustomization.yaml` document's `metadata.namespace` axis
4145 // binds to the lifted [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]) — to
4146 // a re-export of [`caixa_core::KUBE_KEY_NAMESPACE`] so the
4147 // canonical K8s-CR `metadata.namespace` axis string lives in
4148 // exactly one place across every caixa renderer. Pin the
4149 // equality + static-data identity here so any local
4150 // re-introduction of a sibling `pub const KUBE_KEY_NAMESPACE:
4151 // &str = "…"` (the canonical drift footgun where a sibling
4152 // local `pub const` could happen to carry the same string at
4153 // the source while pointing at a different `&'static`
4154 // allocation) is a build-time test failure naming the
4155 // offending drift, not a silent apply-time symptom — the prior
4156 // shape would have let a typo on any one sibling `pub const`
4157 // declaration silently miss the ComputeUnit's
4158 // `metadata.namespace` lookup and fall back to
4159 // [`DEFAULT_NAMESPACE`] even when the ComputeUnit YAML pinned
4160 // a distinct target namespace, or mask the sibling
4161 // [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] drift the
4162 // `kustomization.yaml`-side pin was meant to catch under the
4163 // `.expect("kustomization.yaml present")` panic on the missing
4164 // `.and_then` chain. Peer to
4165 // [`kube_key_spec_re_export_points_at_caixa_core_canonical`] /
4166 // [`kube_key_metadata_re_export_points_at_caixa_core_canonical`]
4167 // / [`kube_key_kind_re_export_points_at_caixa_core_canonical`]
4168 // / [`kube_key_api_version_re_export_points_at_caixa_core_canonical`]
4169 // on the sibling K8s-CR top-level `(spec, metadata, kind,
4170 // apiVersion)` axis re-exports — extends the discipline the
4171 // top-level quartet establishes onto the canonical
4172 // `metadata.namespace` nested axis every rendered Flux v2
4173 // bundle document navigates.
4174 caixa_core::assert_str_reexport_identity(
4175 "KUBE_KEY_NAMESPACE",
4176 KUBE_KEY_NAMESPACE,
4177 caixa_core::KUBE_KEY_NAMESPACE,
4178 );
4179 }
4180
4181 #[test]
4182 fn fleet_programs_key_programs_re_export_points_at_caixa_core_canonical() {
4183 // The renderer's `FLEET_PROGRAMS_KEY_PROGRAMS` was lifted from
4184 // the two inline `"programs"` production-code call sites
4185 // (`upsert_into_helmrelease_programs` at
4186 // `values_map.entry(Value::String("programs".into()))` on the
4187 // aggregator-HelmRelease shape, `upsert_into_programs_yaml` at
4188 // `let programs_key = Value::String("programs".into())` on the
4189 // bare-values.yaml shape) — the two writer-side upsert paths
4190 // that walk `HelmRelease.spec.values.programs[]` /
4191 // top-level `programs[]` to match-by-name-and-replace-or-append.
4192 // Both now navigate through the same `&'static str` as every
4193 // peer consumer, re-exported to a re-export of
4194 // [`caixa_core::FLEET_PROGRAMS_KEY_PROGRAMS`] so the canonical
4195 // `lareira-fleet-programs` values-schema array key lives in
4196 // exactly one place across every caixa renderer + consumer.
4197 // Pin the equality + static-data identity here so any local
4198 // re-introduction of a sibling `pub const FLEET_PROGRAMS_KEY_PROGRAMS:
4199 // &str = "…"` (the canonical drift footgun where a sibling
4200 // local `pub const` could happen to carry the same string at
4201 // the source while pointing at a different `&'static`
4202 // allocation) is a build-time test failure naming the offending
4203 // drift, not a silent apply-time symptom — the prior shape
4204 // would have let a typo on any one sibling `pub const`
4205 // declaration silently emit an entry under one key while the
4206 // peer-side upsert probed a different key, and the aggregator's
4207 // `range .Values.programs` would then iterate an empty sequence
4208 // (every `ComputeUnit` CR silently vanishing from the cluster's
4209 // fleet). Peer to
4210 // [`kube_key_namespace_re_export_points_at_caixa_core_canonical`]
4211 // /
4212 // [`kube_key_spec_re_export_points_at_caixa_core_canonical`] /
4213 // [`kube_key_metadata_re_export_points_at_caixa_core_canonical`]
4214 // /
4215 // [`kube_key_kind_re_export_points_at_caixa_core_canonical`] /
4216 // [`kube_key_api_version_re_export_points_at_caixa_core_canonical`]
4217 // on the sibling K8s-CR top-level axis re-exports — extends
4218 // the discipline the K8s-CR key re-export quintet establishes
4219 // onto the canonical fleet-programs schema top-level axis
4220 // (`programs:`) every rendered aggregator-HelmRelease /
4221 // bare-values.yaml document navigates.
4222 caixa_core::assert_str_reexport_identity(
4223 "FLEET_PROGRAMS_KEY_PROGRAMS",
4224 FLEET_PROGRAMS_KEY_PROGRAMS,
4225 caixa_core::FLEET_PROGRAMS_KEY_PROGRAMS,
4226 );
4227 }
4228
4229 #[test]
4230 fn fleet_programs_key_name_re_export_points_at_caixa_core_canonical() {
4231 // The renderer's `FLEET_PROGRAMS_KEY_NAME` was lifted from the
4232 // three inline `"name"` production-code call sites in
4233 // [`programs_yaml_entry`] (emit-side per-Servico entry.insert
4234 // seeded from `caixa.nome`), [`upsert_into_helmrelease_programs`]
4235 // (writer-side `new_entry.get("name")` / `slot.get("name")` +
4236 // `Error::MissingField("name")` triplet on the aggregator-
4237 // HelmRelease shape), and [`upsert_into_programs_yaml`] (writer-
4238 // side peer triplet on the bare-values.yaml shape) — every
4239 // fleet-programs per-entry name-axis read + write + missing-
4240 // field diagnostic across the two writer-side upsert paths and
4241 // the one emit-side entry builder now navigates through the
4242 // same `&'static str` re-exported to a re-export of
4243 // [`caixa_core::FLEET_PROGRAMS_KEY_NAME`] so the canonical
4244 // `lareira-fleet-programs` values-schema per-entry name-
4245 // discriminator key lives in exactly one place across every
4246 // caixa renderer + consumer. Pin the equality + static-data
4247 // identity here so any local re-introduction of a sibling
4248 // `pub const FLEET_PROGRAMS_KEY_NAME: &str = "…"` (the canonical
4249 // drift footgun where a sibling local `pub const` could happen
4250 // to carry the same string at the source while pointing at a
4251 // different `&'static` allocation) is a build-time test failure
4252 // naming the offending drift, not a silent apply-time symptom —
4253 // the prior shape would have let a typo on any one sibling
4254 // `pub const` declaration silently emit an entry under one key
4255 // while the peer-side upsert probed a different key, and the
4256 // aggregator's `range .Values.programs` would then iterate
4257 // entries whose per-entry name-axis the library chart's
4258 // `metadata.name` templating reads as empty (or match against
4259 // the wrong entry on upsert), collapsing every rendered
4260 // `ComputeUnit` CR at the aggregator's name-keyed reduce step.
4261 // Peer to
4262 // [`fleet_programs_key_programs_re_export_points_at_caixa_core_canonical`]
4263 // on the sibling fleet-programs top-level array-key re-export
4264 // + [`kube_key_namespace_re_export_points_at_caixa_core_canonical`]
4265 // / [`kube_key_spec_re_export_points_at_caixa_core_canonical`]
4266 // on the peer K8s-CR canonical-key re-export surfaces —
4267 // extends the discipline the K8s-CR key re-export quintet +
4268 // the sibling fleet-programs top-level array-key re-export
4269 // establish onto the canonical fleet-programs schema per-entry
4270 // name-discriminator axis.
4271 caixa_core::assert_str_reexport_identity(
4272 "FLEET_PROGRAMS_KEY_NAME",
4273 FLEET_PROGRAMS_KEY_NAME,
4274 caixa_core::FLEET_PROGRAMS_KEY_NAME,
4275 );
4276 }
4277
4278 #[test]
4279 fn computeunit_spec_key_module_re_export_points_at_caixa_core_canonical() {
4280 // The renderer's `COMPUTEUNIT_SPEC_KEY_MODULE` was lifted from
4281 // the four inline `"module"` test-side call sites in this
4282 // crate (`programs_yaml_entry_round_trips`'s per-entry
4283 // `entry.get("module")` present-check + its per-
4284 // `module.source` nested navigator, plus
4285 // `upsert_helmrelease_replaces_existing` /
4286 // `upsert_into_programs_yaml`'s per-`module.source` cross-
4287 // upsert readback navigators) — every per-Servico ComputeUnit
4288 // CRD `spec.module` sub-block readback across the four
4289 // drift-detection navigators now navigates through the same
4290 // `&'static str` re-exported to a re-export of
4291 // [`caixa_core::COMPUTEUNIT_SPEC_KEY_MODULE`]. Pin the
4292 // equality + static-data identity here so any local re-
4293 // introduction of a sibling `pub const COMPUTEUNIT_SPEC_KEY_MODULE:
4294 // &str = "…"` is a build-time test failure naming the
4295 // offending drift, not a silent apply-time symptom. Peer to
4296 // [`fleet_programs_key_programs_re_export_points_at_caixa_core_canonical`]
4297 // /
4298 // [`kube_key_spec_re_export_points_at_caixa_core_canonical`]
4299 // on the sibling fleet-programs / K8s-CR-key re-export
4300 // surfaces — extends the discipline the K8s-CR / fleet-
4301 // programs key re-export families establish onto the
4302 // substrate-side ComputeUnit-CRD per-`spec.*` sub-block axis.
4303 caixa_core::assert_str_reexport_identity(
4304 "COMPUTEUNIT_SPEC_KEY_MODULE",
4305 COMPUTEUNIT_SPEC_KEY_MODULE,
4306 caixa_core::COMPUTEUNIT_SPEC_KEY_MODULE,
4307 );
4308 }
4309
4310 #[test]
4311 fn computeunit_spec_key_trigger_re_export_points_at_caixa_core_canonical() {
4312 // Peer to
4313 // [`computeunit_spec_key_module_re_export_points_at_caixa_core_canonical`]
4314 // on the same ComputeUnit-CRD per-`spec.*` sub-block re-export
4315 // surface — pins the per-Servico invocation-shape sub-block
4316 // key's identity on the same trajectory.
4317 caixa_core::assert_str_reexport_identity(
4318 "COMPUTEUNIT_SPEC_KEY_TRIGGER",
4319 COMPUTEUNIT_SPEC_KEY_TRIGGER,
4320 caixa_core::COMPUTEUNIT_SPEC_KEY_TRIGGER,
4321 );
4322 }
4323
4324 #[test]
4325 fn computeunit_spec_key_capabilities_re_export_points_at_caixa_core_canonical() {
4326 // Peer to
4327 // [`computeunit_spec_key_module_re_export_points_at_caixa_core_canonical`]
4328 // and
4329 // [`computeunit_spec_key_trigger_re_export_points_at_caixa_core_canonical`]
4330 // on the same ComputeUnit-CRD per-`spec.*` sub-block re-export
4331 // surface — completes the substrate-side ComputeUnit-CRD
4332 // per-`spec.*` sub-block re-export triple in this crate on the
4333 // WASI-capability-token-list axis.
4334 caixa_core::assert_str_reexport_identity(
4335 "COMPUTEUNIT_SPEC_KEY_CAPABILITIES",
4336 COMPUTEUNIT_SPEC_KEY_CAPABILITIES,
4337 caixa_core::COMPUTEUNIT_SPEC_KEY_CAPABILITIES,
4338 );
4339 }
4340
4341 #[test]
4342 fn computeunit_module_key_source_re_export_points_at_caixa_core_canonical() {
4343 // The renderer's `COMPUTEUNIT_MODULE_KEY_SOURCE` was lifted
4344 // from the three inline `"source"` test-side call sites in
4345 // this crate — `programs_yaml_entry_round_trips`'s per-entry
4346 // `.get(COMPUTEUNIT_SPEC_KEY_MODULE).and_then(|m| m.get("source"))`
4347 // present-check + `upsert_replaces_existing_entry`'s per-
4348 // `arr[0].get(COMPUTEUNIT_SPEC_KEY_MODULE).get("source")`
4349 // cross-upsert readback + `upsert_helmrelease_inserts_under_spec_values_programs`'s
4350 // peer `HelmRelease`-wrapped `spec.values.programs[]` cross-
4351 // upsert readback. Every per-Servico ComputeUnit-CRD
4352 // `spec.module.source` leaf-scalar readback across the three
4353 // drift-detection navigators now navigates through the same
4354 // `&'static str` re-exported to a re-export of
4355 // [`caixa_core::COMPUTEUNIT_MODULE_KEY_SOURCE`]. Pin the
4356 // equality + static-data identity here so any local re-
4357 // introduction of a sibling `pub const COMPUTEUNIT_MODULE_KEY_SOURCE:
4358 // &str = "…"` is a build-time test failure naming the
4359 // offending drift, not a silent apply-time symptom. Peer to
4360 // [`computeunit_spec_key_module_re_export_points_at_caixa_core_canonical`]
4361 // on the same ComputeUnit-CRD family — extends the re-export-
4362 // identity gate one level deeper from the top-level `spec.*`
4363 // container-axis surface onto the nested `spec.module.*`
4364 // leaf-scalar-axis.
4365 caixa_core::assert_str_reexport_identity(
4366 "COMPUTEUNIT_MODULE_KEY_SOURCE",
4367 COMPUTEUNIT_MODULE_KEY_SOURCE,
4368 caixa_core::COMPUTEUNIT_MODULE_KEY_SOURCE,
4369 );
4370 }
4371
4372 #[test]
4373 fn programs_yaml_entry_round_trips() {
4374 let entry = programs_yaml_entry(&sample_caixa(), &sample_cu_yaml()).unwrap();
4375 assert_eq!(
4376 entry.get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()),
4377 Some("hello-rio")
4378 );
4379 assert_eq!(
4380 entry.get(KUBE_KEY_NAMESPACE).and_then(|n| n.as_str()),
4381 Some(DEFAULT_NAMESPACE)
4382 );
4383 assert!(entry.get(COMPUTEUNIT_SPEC_KEY_MODULE).is_some());
4384 assert!(entry.get(COMPUTEUNIT_SPEC_KEY_TRIGGER).is_some());
4385 assert!(entry.get(COMPUTEUNIT_SPEC_KEY_CAPABILITIES).is_some());
4386 assert!(
4387 entry
4388 .get(COMPUTEUNIT_SPEC_KEY_MODULE)
4389 .and_then(|m| m.get(COMPUTEUNIT_MODULE_KEY_SOURCE))
4390 .is_some(),
4391 "module.source must propagate verbatim"
4392 );
4393 }
4394
4395 #[test]
4396 fn programs_yaml_entry_falls_back_to_default_namespace() {
4397 // A computeunit without metadata.namespace should default.
4398 let cu: serde_yaml::Value = serde_yaml::from_str(
4399 r#"
4400apiVersion: wasm.pleme.io/v1alpha1
4401kind: ComputeUnit
4402metadata:
4403 name: hello-rio
4404spec:
4405 module:
4406 source: oci://ghcr.io/pleme-io/hello-rio:v0.1.0
4407"#,
4408 )
4409 .unwrap();
4410 let entry = programs_yaml_entry(&sample_caixa(), &cu).unwrap();
4411 assert_eq!(
4412 entry.get(KUBE_KEY_NAMESPACE).and_then(|n| n.as_str()),
4413 Some(DEFAULT_NAMESPACE)
4414 );
4415 }
4416
4417 #[test]
4418 fn programs_yaml_entry_refuses_non_servico() {
4419 let mut c = sample_caixa();
4420 c.kind = CaixaKind::Biblioteca;
4421 c.servicos = vec![];
4422 let err = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap_err();
4423 assert!(matches!(err, Error::NotAServico(_)));
4424 }
4425
4426 #[test]
4427 fn kind_mismatch_error_names_offending_caixa_nome() {
4428 // Pinning the lifted [`caixa_core::KindMismatch`] view's
4429 // load-bearing property: a kind-mismatched caixa surfaces a
4430 // diagnostic that *names the offending caixa* (`hello-rio`),
4431 // not just the rejected kind. Before the lift the renderer
4432 // raised `Error::NotAServico(CaixaKind::Biblioteca)` whose
4433 // Display said "caixa :kind must be Servico for caixa-flux
4434 // rendering, got Biblioteca" — the user had to grep their
4435 // source tree for which caixa.lisp triggered it. After the
4436 // lift the wrapped KindMismatch carries the `:nome`, the
4437 // renderer's `#[error("{0}")]` arm prints it through, and
4438 // the diagnostic is self-locating.
4439 let mut c = sample_caixa();
4440 c.kind = CaixaKind::Biblioteca;
4441 c.servicos = vec![];
4442 let err = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap_err();
4443 let msg = format!("{err}");
4444 assert!(
4445 msg.contains("hello-rio"),
4446 "kind-mismatch diagnostic must name the offending caixa nome \
4447 (got: {msg:?})"
4448 );
4449 assert!(
4450 msg.contains("Servico"),
4451 "diagnostic must name the expected kind (got: {msg:?})"
4452 );
4453 assert!(
4454 msg.contains("Biblioteca"),
4455 "diagnostic must name the actual kind (got: {msg:?})"
4456 );
4457 }
4458
4459 #[test]
4460 fn cluster_bundle_kind_mismatch_names_offending_caixa_nome() {
4461 // The second kind-checking call site in caixa-flux —
4462 // [`cluster_bundle`] — must surface the same lifted diagnostic
4463 // shape. Pinning so a future divergence between
4464 // `programs_yaml_entry` and `cluster_bundle` (e.g. one
4465 // re-inlines the kind check, the other uses `require_kind`)
4466 // surfaces here as a test failure rather than as a silent
4467 // diagnostic regression on the deploy path.
4468 let mut c = sample_caixa();
4469 c.kind = CaixaKind::Aplicacao;
4470 c.servicos = vec![];
4471 let opts = ClusterBundleOpts::for_caixa(&c, "rio");
4472 let err = cluster_bundle(&c, &opts).unwrap_err();
4473 let msg = format!("{err}");
4474 assert!(
4475 msg.contains("hello-rio"),
4476 "cluster_bundle's kind-mismatch must also name the caixa \
4477 nome (got: {msg:?})"
4478 );
4479 match err {
4480 Error::NotAServico(km) => {
4481 assert_eq!(km.nome, "hello-rio");
4482 assert_eq!(km.expected, CaixaKind::Servico);
4483 assert_eq!(km.actual, CaixaKind::Aplicacao);
4484 }
4485 other => panic!("expected Error::NotAServico, got {other:?}"),
4486 }
4487 }
4488
4489 #[test]
4490 fn servico_count_mismatch_carries_typed_view_with_nome() {
4491 // Peer to the [`KindMismatch`]-lift pin above on the V0
4492 // `:servicos`-singularity axis: a Servico-kind caixa whose
4493 // `:servicos` list is non-singleton fails
4494 // [`programs_yaml_entry`] with the renderer's
4495 // `Error::UnsupportedServicoCount` variant wrapping the typed
4496 // [`caixa_core::ServicoCountMismatch`] view (carrying the
4497 // offending caixa's `:nome` + the actual count). Before the
4498 // lift the variant carried only `usize` — the user had to grep
4499 // their source tree for which `caixa.lisp` triggered it; after
4500 // the lift the wrapped typed view names the offending caixa
4501 // verbatim. Pins both the variant routing (via `#[from]`) and
4502 // the typed payload so a future refactor can't silently switch
4503 // back to the raw-`usize` payload (which would regress the
4504 // shared-shape contract with caixa-helm on the peer
4505 // `lareira-<nome>` chart-dir path).
4506 let mut c = sample_caixa();
4507 c.servicos = vec![
4508 "servicos/hello-rio.computeunit.yaml".into(),
4509 "servicos/extra.computeunit.yaml".into(),
4510 ];
4511 let err = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap_err();
4512 match err {
4513 Error::UnsupportedServicoCount(scm) => {
4514 assert_eq!(scm.nome, "hello-rio");
4515 assert_eq!(scm.count, 2);
4516 }
4517 other => panic!("expected Error::UnsupportedServicoCount, got {other:?}"),
4518 }
4519 }
4520
4521 #[test]
4522 fn servico_count_mismatch_diagnostic_names_offending_caixa_nome() {
4523 // The renderer's `#[error("{0}")] UnsupportedServicoCount(
4524 // #[from] ServicoCountMismatch)` arm prints the typed view's
4525 // Display through verbatim, so the offending caixa's `:nome`
4526 // appears in the rendered diagnostic on both the
4527 // `programs_yaml_entry` and `cluster_bundle` paths. Pinning the
4528 // self-locating property end-to-end so a future refactor that
4529 // re-wraps the variant in a Display impl that drops the
4530 // `:nome` surfaces here as a test failure rather than as
4531 // silent fragmentation across the two flux deploy paths. Peer
4532 // to `cluster_bundle_kind_mismatch_names_offending_caixa_nome`
4533 // on the sibling V0 Servico-shape axis.
4534 let mut c = sample_caixa();
4535 c.servicos = vec![];
4536 let err = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap_err();
4537 let msg = format!("{err}");
4538 assert!(
4539 msg.contains("hello-rio"),
4540 ":servicos-count-mismatch diagnostic must name the offending caixa nome \
4541 (got: {msg:?})"
4542 );
4543 assert!(
4544 msg.contains("0"),
4545 "diagnostic must name the actual count (got: {msg:?})"
4546 );
4547 assert!(
4548 msg.contains(":servicos"),
4549 "diagnostic must name the offending field axis (got: {msg:?})"
4550 );
4551 }
4552
4553 #[test]
4554 fn cluster_bundle_servico_count_mismatch_carries_typed_view_with_nome() {
4555 // Peer to `cluster_bundle_kind_mismatch_names_offending_caixa_nome`
4556 // on the sibling V0 `:servicos`-singularity axis. The second
4557 // per-Servico renderer entry-point in caixa-flux —
4558 // [`cluster_bundle`] — must surface the same lifted
4559 // [`caixa_core::ServicoCountMismatch`] view the peer
4560 // [`programs_yaml_entry`] path already pins on the sibling V0
4561 // gate axis. Until this gate landed `cluster_bundle` ran only
4562 // the [`require_kind`] half of the V0-shape gate pair, so a
4563 // Servico-kind caixa whose `:servicos` list is non-singleton
4564 // silently passed the bundle render and the failure surfaced at
4565 // the chart-render layer (`caixa-helm` refused the same input
4566 // with `UnsupportedServicoCount`) far from the deploy-path
4567 // entry-point — the canonical "the V0 invariant is enforced at
4568 // every per-Servico renderer entry except this one" footgun.
4569 // Pins both the variant routing (via `#[from]`) and the typed
4570 // payload so a future refactor that re-inlines a raw count
4571 // check, or strips the `require_single_servico` call from this
4572 // path, surfaces here as a test failure rather than as silent
4573 // fragmentation across the two flux deploy paths.
4574 let mut c = sample_caixa();
4575 c.servicos = vec![
4576 "servicos/hello-rio.computeunit.yaml".into(),
4577 "servicos/extra.computeunit.yaml".into(),
4578 ];
4579 let opts = ClusterBundleOpts::for_caixa(&c, "rio");
4580 let err = cluster_bundle(&c, &opts).unwrap_err();
4581 match err {
4582 Error::UnsupportedServicoCount(scm) => {
4583 assert_eq!(scm.nome, "hello-rio");
4584 assert_eq!(scm.count, 2);
4585 }
4586 other => panic!("expected Error::UnsupportedServicoCount, got {other:?}"),
4587 }
4588 }
4589
4590 #[test]
4591 fn cluster_bundle_servico_count_mismatch_diagnostic_names_offending_caixa_nome() {
4592 // End-to-end Display pin on the [`cluster_bundle`] path —
4593 // peer of `servico_count_mismatch_diagnostic_names_offending_caixa_nome`
4594 // on the sibling [`programs_yaml_entry`] path. The rendered
4595 // diagnostic must name the offending caixa's `:nome`, the
4596 // actual count, and the `:servicos` field axis verbatim on
4597 // both per-Servico renderer entry-points in caixa-flux. Peer
4598 // to `cluster_bundle_kind_mismatch_names_offending_caixa_nome`
4599 // on the sibling V0 kind-shape axis — both V0 gate arms now
4600 // pin their self-locating diagnostic shape end-to-end through
4601 // the bundle path.
4602 let mut c = sample_caixa();
4603 c.servicos = vec![];
4604 let opts = ClusterBundleOpts::for_caixa(&c, "rio");
4605 let err = cluster_bundle(&c, &opts).unwrap_err();
4606 let msg = format!("{err}");
4607 assert!(
4608 msg.contains("hello-rio"),
4609 "cluster_bundle's :servicos-count-mismatch must name the offending caixa nome \
4610 (got: {msg:?})"
4611 );
4612 assert!(
4613 msg.contains("0"),
4614 "diagnostic must name the actual count (got: {msg:?})"
4615 );
4616 assert!(
4617 msg.contains(":servicos"),
4618 "diagnostic must name the offending field axis (got: {msg:?})"
4619 );
4620 }
4621
4622 #[test]
4623 fn upsert_inserts_new_entry() {
4624 let initial: serde_yaml::Value = serde_yaml::from_str(
4625 r#"
4626enabled: true
4627defaultNamespace: tatara-system
4628programs: []
4629"#,
4630 )
4631 .unwrap();
4632 let entry = programs_yaml_entry(&sample_caixa(), &sample_cu_yaml()).unwrap();
4633 let (modified, inserted) = upsert_into_programs_yaml(initial, entry).unwrap();
4634 assert!(inserted, "first time should be insert");
4635 let arr = modified
4636 .get(FLEET_PROGRAMS_KEY_PROGRAMS)
4637 .unwrap()
4638 .as_sequence()
4639 .unwrap();
4640 assert_eq!(arr.len(), 1);
4641 assert_eq!(
4642 arr[0].get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()),
4643 Some("hello-rio")
4644 );
4645 }
4646
4647 #[test]
4648 fn upsert_replaces_existing_entry() {
4649 let initial: serde_yaml::Value = serde_yaml::from_str(
4650 r#"
4651enabled: true
4652defaultNamespace: tatara-system
4653programs:
4654 - name: hello-rio
4655 namespace: tatara-system
4656 module:
4657 source: oci://ghcr.io/pleme-io/hello-rio:v0.0.1
4658 - name: other
4659 namespace: tatara-system
4660 module: { source: github:foo/bar }
4661"#,
4662 )
4663 .unwrap();
4664 let entry = programs_yaml_entry(&sample_caixa(), &sample_cu_yaml()).unwrap();
4665 let (modified, inserted) = upsert_into_programs_yaml(initial, entry).unwrap();
4666 assert!(!inserted, "second time should be replace");
4667 let arr = modified
4668 .get(FLEET_PROGRAMS_KEY_PROGRAMS)
4669 .unwrap()
4670 .as_sequence()
4671 .unwrap();
4672 assert_eq!(arr.len(), 2, "no new entry added");
4673 let updated_module = arr[0]
4674 .get(COMPUTEUNIT_SPEC_KEY_MODULE)
4675 .unwrap()
4676 .get(COMPUTEUNIT_MODULE_KEY_SOURCE)
4677 .and_then(|s| s.as_str());
4678 assert_eq!(
4679 updated_module,
4680 Some("oci://ghcr.io/pleme-io/hello-rio:v0.1.0")
4681 );
4682 }
4683
4684 #[test]
4685 fn upsert_helmrelease_inserts_under_spec_values_programs() {
4686 let initial: serde_yaml::Value = serde_yaml::from_str(
4687 r#"
4688apiVersion: helm.toolkit.fluxcd.io/v2
4689kind: HelmRelease
4690metadata:
4691 name: rio-fleet-programs
4692 namespace: tatara-system
4693spec:
4694 interval: 30m
4695 chart:
4696 spec:
4697 chart: lareira-fleet-programs
4698 values:
4699 enabled: true
4700 defaultNamespace: tatara-system
4701 programs:
4702 - name: existing
4703 module: { source: github:foo/bar }
4704"#,
4705 )
4706 .unwrap();
4707 let entry = programs_yaml_entry(&sample_caixa(), &sample_cu_yaml()).unwrap();
4708 let (modified, inserted) = upsert_into_helmrelease_programs(initial, entry).unwrap();
4709 assert!(inserted);
4710 let arr = modified
4711 .get(KUBE_KEY_SPEC)
4712 .unwrap()
4713 .get(FLUX_KEY_VALUES)
4714 .unwrap()
4715 .get(FLEET_PROGRAMS_KEY_PROGRAMS)
4716 .unwrap()
4717 .as_sequence()
4718 .unwrap();
4719 assert_eq!(arr.len(), 2);
4720 assert_eq!(
4721 arr[1].get(FLEET_PROGRAMS_KEY_NAME).and_then(|n| n.as_str()),
4722 Some("hello-rio")
4723 );
4724 }
4725
4726 #[test]
4727 fn upsert_helmrelease_replaces_existing() {
4728 let initial: serde_yaml::Value = serde_yaml::from_str(
4729 r#"
4730apiVersion: helm.toolkit.fluxcd.io/v2
4731kind: HelmRelease
4732metadata: { name: rio-fleet-programs }
4733spec:
4734 values:
4735 programs:
4736 - name: hello-rio
4737 module: { source: oci://ghcr.io/pleme-io/hello-rio:v0.0.1 }
4738 - name: other
4739 module: { source: github:foo/bar }
4740"#,
4741 )
4742 .unwrap();
4743 let entry = programs_yaml_entry(&sample_caixa(), &sample_cu_yaml()).unwrap();
4744 let (modified, inserted) = upsert_into_helmrelease_programs(initial, entry).unwrap();
4745 assert!(!inserted);
4746 let arr = modified
4747 .get(KUBE_KEY_SPEC)
4748 .unwrap()
4749 .get(FLUX_KEY_VALUES)
4750 .unwrap()
4751 .get(FLEET_PROGRAMS_KEY_PROGRAMS)
4752 .unwrap()
4753 .as_sequence()
4754 .unwrap();
4755 assert_eq!(arr.len(), 2);
4756 let updated = arr[0]
4757 .get(COMPUTEUNIT_SPEC_KEY_MODULE)
4758 .unwrap()
4759 .get(COMPUTEUNIT_MODULE_KEY_SOURCE)
4760 .and_then(|s| s.as_str());
4761 assert_eq!(updated, Some("oci://ghcr.io/pleme-io/hello-rio:v0.1.0"));
4762 }
4763
4764 #[test]
4765 fn limits_slot_propagates_into_programs_yaml_entry() {
4766 use caixa_core::LimitsSpec;
4767 use std::time::Duration;
4768 let mut c = sample_caixa();
4769 c.limits = Some(LimitsSpec {
4770 memory: Some(64 * 1024 * 1024),
4771 fuel: Some(1_000_000),
4772 wall_clock: Some(Duration::from_secs(30)),
4773 cpu: Some(500),
4774 });
4775 let entry = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap();
4776 let limits = entry.get(M2_KEY_LIMITS).expect("limits propagates");
4777 assert_eq!(
4778 limits.get(M2_LIMITS_KEY_MEMORY).and_then(|m| m.as_str()),
4779 Some("64MiB")
4780 );
4781 assert_eq!(
4782 limits.get(M2_LIMITS_KEY_CPU).and_then(|m| m.as_str()),
4783 Some("500m")
4784 );
4785 }
4786
4787 #[test]
4788 fn behavior_slot_propagates_into_programs_yaml_entry() {
4789 use caixa_core::BehaviorSpec;
4790 use std::path::PathBuf;
4791 let mut c = sample_caixa();
4792 c.behavior = Some(BehaviorSpec {
4793 on_init: Some(PathBuf::from("lib/init.lisp")),
4794 on_state_change: Some(PathBuf::from("lib/migrations.lisp")),
4795 ..Default::default()
4796 });
4797 let entry = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap();
4798 let behavior = entry.get(M2_KEY_BEHAVIOR).expect("behavior propagates");
4799 assert_eq!(
4800 behavior
4801 .get(M2_BEHAVIOR_KEY_ON_INIT)
4802 .and_then(|v| v.as_str()),
4803 Some("lib/init.lisp")
4804 );
4805 }
4806
4807 #[test]
4808 fn upgrade_from_slot_propagates_into_programs_yaml_entry() {
4809 use caixa_core::{UpgradeFromEntry, UpgradeInstruction};
4810 let mut c = sample_caixa();
4811 c.upgrade_from = vec![UpgradeFromEntry {
4812 from: "0.0.9".into(),
4813 instructions: vec![UpgradeInstruction::SoftPurge {
4814 module: "hello-rio-old".into(),
4815 }],
4816 }];
4817 let entry = programs_yaml_entry(&c, &sample_cu_yaml()).unwrap();
4818 let upgrade_from = entry
4819 .get(M2_KEY_UPGRADE_FROM)
4820 .and_then(|u| u.as_sequence())
4821 .expect("upgradeFrom propagates as a sequence");
4822 assert_eq!(upgrade_from.len(), 1);
4823 assert_eq!(
4824 upgrade_from[0]
4825 .get(M2_UPGRADE_FROM_KEY_FROM)
4826 .and_then(|f| f.as_str()),
4827 Some("0.0.9")
4828 );
4829 }
4830
4831 #[test]
4832 fn empty_m2_slots_do_not_appear_in_programs_yaml_entry() {
4833 // Forward-compat invariant: a Servico with no M2 slots emits a
4834 // programs.yaml entry that's structurally identical to V0
4835 // (no extra keys).
4836 let entry = programs_yaml_entry(&sample_caixa(), &sample_cu_yaml()).unwrap();
4837 assert!(entry.get(M2_KEY_LIMITS).is_none());
4838 assert!(entry.get(M2_KEY_BEHAVIOR).is_none());
4839 assert!(entry.get(M2_KEY_UPGRADE_FROM).is_none());
4840 }
4841
4842 #[test]
4843 fn cluster_bundle_three_files() {
4844 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
4845 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
4846 assert_eq!(files.len(), 3);
4847 let names: Vec<_> = files
4848 .iter()
4849 .map(|f| f.path.to_string_lossy().to_string())
4850 .collect();
4851 assert!(names.contains(&FLUX_GITREPOSITORY_YAML_FILENAME.to_string()));
4852 assert!(names.contains(&FLUX_HELMRELEASE_YAML_FILENAME.to_string()));
4853 assert!(names.contains(&FLUX_KUSTOMIZATION_YAML_FILENAME.to_string()));
4854
4855 let kust = files
4856 .iter()
4857 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
4858 .unwrap();
4859 assert!(kust.contents.contains("./clusters/rio/services/hello-rio"));
4860
4861 let gitrepo = files
4862 .iter()
4863 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
4864 .unwrap();
4865 assert!(gitrepo.contents.contains("v0.1.0"));
4866 }
4867
4868 #[test]
4869 fn default_library_name_re_export_points_at_caixa_core_canonical() {
4870 // The renderer's `pub use caixa_core::DEFAULT_LIBRARY_NAME` is
4871 // the single source of truth for the Helm library-chart wrap
4872 // key the `cluster_bundle` `helmrelease.yaml` template scopes
4873 // the per-cluster `enabled: true` override under. Pin the
4874 // equality (and the static-data identity, peer with the
4875 // sibling `default_namespace_re_export_points_at_caixa_core_canonical`
4876 // pin) so any local re-introduction of a sibling `pub const
4877 // DEFAULT_LIBRARY_NAME: &str = "…"` (the canonical drift
4878 // footgun this lift closes — two production-code consumers of
4879 // the same load-bearing Helm library-chart name across
4880 // caixa-helm + caixa-flux, lifted to one re-export at the
4881 // caixa-core boundary) is a build-time test failure naming
4882 // the offending drift, not a silent apply-time wrap-key
4883 // mismatch routing the per-cluster override nowhere. Peer to
4884 // `caixa_helm::tests::default_library_name_re_export_points_at_caixa_core_canonical`
4885 // on the sibling renderer crate.
4886 caixa_core::assert_str_reexport_identity(
4887 "DEFAULT_LIBRARY_NAME",
4888 DEFAULT_LIBRARY_NAME,
4889 caixa_core::DEFAULT_LIBRARY_NAME,
4890 );
4891 }
4892
4893 #[test]
4894 fn cluster_bundle_helmrelease_values_wrap_key_uses_lifted_constant() {
4895 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`'s
4896 // `spec.values.<library>:` wrap key — the scope under which
4897 // per-cluster overrides like `enabled: true` reach the
4898 // dependent library chart at `helm template` / `helm install`
4899 // time — must spell out the lifted [`DEFAULT_LIBRARY_NAME`]
4900 // verbatim. Before the lift this site carried an inline
4901 // `pleme-computeunit:` literal in the format string; a future
4902 // per-edition library-chart rebrand (the substrate forking
4903 // `pleme-computeunit` to `<registry>-computeunit` for a per-
4904 // cluster image-registry mirror, or to `aplicacao-computeunit`
4905 // for the M4 typed-Aplicacao renderer's sibling library chart,
4906 // or any per-tenant variant the absorption-roadmap names) on
4907 // the sibling caixa-helm `RenderOpts::library_name` axis
4908 // without a coordinated edit here would have silently routed
4909 // the per-cluster override nowhere — the cluster's apply would
4910 // come up with the library chart's defaults, far from the
4911 // rebrand commit's source.
4912 //
4913 // The pin is structural: parse the rendered YAML and assert
4914 // the wrap key under `spec.values` equals the lifted constant.
4915 // A regression that re-introduces an inline literal surfaces
4916 // as a key mismatch (the inline literal would survive, but
4917 // the lifted-constant-keyed assertion would fail).
4918 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
4919 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
4920 let hr = files
4921 .iter()
4922 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
4923 .expect("helmrelease.yaml present");
4924 let parsed: serde_yaml::Value =
4925 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
4926 let values = parsed
4927 .get(KUBE_KEY_SPEC)
4928 .and_then(|s| s.get(FLUX_KEY_VALUES))
4929 .and_then(|v| v.as_mapping())
4930 .expect("spec.values mapping present");
4931 assert!(
4932 values.get(DEFAULT_LIBRARY_NAME).is_some(),
4933 "spec.values must wrap under the lifted DEFAULT_LIBRARY_NAME \
4934 ({DEFAULT_LIBRARY_NAME:?}); a drifted literal here silently \
4935 routes per-cluster overrides nowhere at helm template time"
4936 );
4937 // The wrapped block must carry the canonical `enabled: true`
4938 // overlay — the per-cluster override the bundle path threads
4939 // through. Pin the round-trip so a refactor that hoists the
4940 // overlay out of the wrap can't silently drop it.
4941 let wrapped = values
4942 .get(DEFAULT_LIBRARY_NAME)
4943 .and_then(|v| v.as_mapping())
4944 .expect("wrapped library mapping");
4945 assert_eq!(
4946 wrapped
4947 .get(HELM_VALUES_KEY_ENABLED)
4948 .and_then(|v| v.as_bool()),
4949 Some(CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT),
4950 "cluster_bundle helmrelease.yaml `spec.values.<library>.enabled` \
4951 overlay must resolve to the lifted \
4952 CLUSTER_BUNDLE_LAREIRA_ENABLED_DEFAULT — a drifted inline \
4953 literal here would silently disagree with the substrate-side \
4954 child-chart force-on-under-composition seed"
4955 );
4956 }
4957
4958 #[test]
4959 fn cluster_bundle_helmrelease_wrap_key_pins_canonical_pleme_computeunit_string() {
4960 // Bridge-arm pin: the lifted [`DEFAULT_LIBRARY_NAME`] constant
4961 // resolves to the canonical `"pleme-computeunit"` string today,
4962 // and the rendered `helmrelease.yaml`'s wrap key must spell
4963 // it out verbatim. Pin the literal here (peer with the
4964 // [`caixa_helm::tests::values_yaml_wraps_under_pleme_computeunit_key`]
4965 // canonical-default arm on the chart-render side) so a future
4966 // rebrand of the lifted constant surfaces here as a coordinated
4967 // edit-point — same trajectory as the
4968 // `default_servico_port_constant_pins_canonical_8080_literal`
4969 // bridge-arm pin in caixa-core.
4970 assert_eq!(DEFAULT_LIBRARY_NAME, "pleme-computeunit");
4971 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
4972 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
4973 let hr = files
4974 .iter()
4975 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
4976 .unwrap();
4977 assert!(
4978 hr.contents.contains("pleme-computeunit:"),
4979 "helmrelease.yaml must spell the canonical library-chart wrap \
4980 key under spec.values (got: {contents:?})",
4981 contents = hr.contents
4982 );
4983 }
4984
4985 #[test]
4986 fn helm_values_key_enabled_re_export_points_at_caixa_core_canonical() {
4987 // The renderer's `HELM_VALUES_KEY_ENABLED` was lifted from the
4988 // production-code inline `enabled: true\n` fragment inside
4989 // [`cluster_bundle`]'s `helmrelease.yaml` format-string template
4990 // (formerly `caixa-flux/src/lib.rs:844`) plus its test-side
4991 // round-trip navigator
4992 // (`cluster_bundle_helmrelease_values_wrap_key_uses_lifted_constant`,
4993 // where `.get("enabled")`
4994 // isolated the per-cluster override the bundle path threads
4995 // through) to a re-export of
4996 // [`caixa_core::HELM_VALUES_KEY_ENABLED`] so the canonical
4997 // `pleme-computeunit` library-chart values-block enable-toggle
4998 // key lives in exactly one place across every caixa renderer.
4999 // Pin the equality + `&'static` static-data identity here so any
5000 // local re-introduction of a sibling
5001 // `pub const HELM_VALUES_KEY_ENABLED: &str = "…"` at this crate
5002 // — the canonical drift footgun where a sibling local
5003 // `pub const` could happen to carry the same string at the
5004 // source while pointing at a different `&'static` allocation —
5005 // is a build-time test failure naming the offending drift, not
5006 // a silent per-values enable-toggle reroute at `helm template` /
5007 // `helm install` time far from the drift site. Peer to
5008 // [`default_library_name_re_export_points_at_caixa_core_canonical`]
5009 // / [`kube_key_spec_re_export_points_at_caixa_core_canonical`] on
5010 // the sibling re-export axes +
5011 // `caixa_helm::tests::helm_values_key_enabled_re_export_points_at_caixa_core_canonical`
5012 // on the peer per-Servico-chart renderer crate.
5013 caixa_core::assert_str_reexport_identity(
5014 "HELM_VALUES_KEY_ENABLED",
5015 HELM_VALUES_KEY_ENABLED,
5016 caixa_core::HELM_VALUES_KEY_ENABLED,
5017 );
5018 }
5019
5020 #[test]
5021 fn default_flux_system_namespace_re_export_points_at_caixa_core_canonical() {
5022 // The renderer's `pub use caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE`
5023 // is the single source of truth for the FluxCD installation
5024 // namespace both axes of the rendered `kustomization.yaml`
5025 // document (`metadata.namespace` and `spec.sourceRef.name`)
5026 // consume. Pin the equality (and the static-data identity, peer
5027 // with the sibling
5028 // `default_namespace_re_export_points_at_caixa_core_canonical` /
5029 // `default_library_name_re_export_points_at_caixa_core_canonical`
5030 // pins) so any local re-introduction of a sibling `pub const
5031 // DEFAULT_FLUX_SYSTEM_NAMESPACE: &str = "…"` (the canonical
5032 // drift footgun this lift closes — two production-code
5033 // consumers of the same load-bearing FluxCD-installation-
5034 // namespace inside the kustomization template, lifted to one
5035 // re-export at the caixa-core boundary) is a build-time test
5036 // failure naming the offending drift, not a silent apply-time
5037 // `Kustomization`-outside-controller-watch-window / dangling-
5038 // `sourceRef` reconciliation freeze.
5039 caixa_core::assert_str_reexport_identity(
5040 "DEFAULT_FLUX_SYSTEM_NAMESPACE",
5041 DEFAULT_FLUX_SYSTEM_NAMESPACE,
5042 caixa_core::DEFAULT_FLUX_SYSTEM_NAMESPACE,
5043 );
5044 }
5045
5046 #[test]
5047 fn cluster_bundle_kustomization_uses_lifted_flux_system_namespace() {
5048 // Fail-before-pass-after pin: the rendered `kustomization.yaml`'s
5049 // `metadata.namespace` and `spec.sourceRef.name` axes — the two
5050 // physical sites the inline `flux-system` literal previously
5051 // sat at (caixa-flux/src/lib.rs:477, 483 in the prior shape) —
5052 // must both resolve to the lifted
5053 // [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] verbatim. Before this lift
5054 // the kustomization template carried two inline `flux-system`
5055 // literals; a future per-cluster Flux installation rebrand on
5056 // either axis without a coordinated edit on the other would have
5057 // silently emitted a `Kustomization` outside the bootstrap
5058 // controller's watch window (the `kustomize-controller` watches
5059 // the installation namespace by default) or a dangling
5060 // `spec.sourceRef.name` pointing at a `GitRepository` that
5061 // doesn't exist in the rebranded namespace.
5062 //
5063 // The pin is structural: parse the rendered YAML and assert
5064 // each of the two axes equals the lifted constant by value. A
5065 // regression that re-introduces an inline literal at either
5066 // axis surfaces here as a key mismatch (the inline literal
5067 // would survive, but the lifted-constant-keyed assertion would
5068 // fail when the lift's value changes).
5069 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5070 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5071 let kust = files
5072 .iter()
5073 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
5074 .expect("kustomization.yaml present");
5075 let parsed: serde_yaml::Value =
5076 serde_yaml::from_str(&kust.contents).expect("kustomization.yaml parses as YAML");
5077 assert_eq!(
5078 kube_metadata_str_field(&parsed, KUBE_KEY_NAMESPACE),
5079 Some(DEFAULT_FLUX_SYSTEM_NAMESPACE),
5080 "kustomization.yaml metadata.namespace must spell the lifted \
5081 DEFAULT_FLUX_SYSTEM_NAMESPACE ({DEFAULT_FLUX_SYSTEM_NAMESPACE:?}); \
5082 a drifted literal here silently places the Kustomization outside \
5083 the bootstrap kustomize-controller's watch window"
5084 );
5085 assert_eq!(
5086 parsed
5087 .get(KUBE_KEY_SPEC)
5088 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
5089 .and_then(|r| r.get("name"))
5090 .and_then(|n| n.as_str()),
5091 Some(DEFAULT_FLUX_SYSTEM_NAMESPACE),
5092 "kustomization.yaml spec.sourceRef.name must spell the lifted \
5093 DEFAULT_FLUX_SYSTEM_NAMESPACE ({DEFAULT_FLUX_SYSTEM_NAMESPACE:?}); \
5094 a drifted literal here dangles the reference at a GitRepository \
5095 that doesn't exist in the rebranded installation namespace"
5096 );
5097 }
5098
5099 #[test]
5100 fn cluster_bundle_kustomization_pins_canonical_flux_system_string() {
5101 // Bridge-arm pin: the lifted [`DEFAULT_FLUX_SYSTEM_NAMESPACE`]
5102 // constant resolves to the canonical `"flux-system"` string
5103 // today, and both rendered `kustomization.yaml` axes must spell
5104 // it out verbatim. Pin the literal here (peer with the
5105 // [`default_flux_system_namespace_pins_canonical_value`]
5106 // canonical-default arm in caixa-core, and with
5107 // [`cluster_bundle_helmrelease_wrap_key_pins_canonical_pleme_computeunit_string`]
5108 // on the sibling `DEFAULT_LIBRARY_NAME` axis) so a future
5109 // rebrand of the lifted constant surfaces here as a coordinated
5110 // edit-point, same trajectory as the
5111 // `default_servico_port_constant_pins_canonical_8080_literal`
5112 // bridge-arm pin in caixa-core.
5113 assert_eq!(DEFAULT_FLUX_SYSTEM_NAMESPACE, "flux-system");
5114 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5115 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5116 let kust = files
5117 .iter()
5118 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
5119 .unwrap();
5120 assert!(
5121 kust.contents.contains("namespace: flux-system\n"),
5122 "kustomization.yaml must spell the canonical FluxCD \
5123 installation namespace at metadata.namespace (got: {contents:?})",
5124 contents = kust.contents
5125 );
5126 assert!(
5127 kust.contents.contains("name: flux-system\n"),
5128 "kustomization.yaml must spell the canonical FluxCD \
5129 installation namespace at spec.sourceRef.name (got: {contents:?})",
5130 contents = kust.contents
5131 );
5132 }
5133
5134 #[test]
5135 fn cluster_bundle_helmrelease_uses_lifted_flux_api_version() {
5136 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`
5137 // `apiVersion` axis — the load-bearing Flux v2 CRD-group/version
5138 // declaration the `helm-controller` watches — must resolve to the
5139 // lifted [`FLUX_HELMRELEASE_API_VERSION`] verbatim. Before this
5140 // lift the helmrelease template carried an inline
5141 // `helm.toolkit.fluxcd.io/v2` literal; a future upstream Flux v3
5142 // migration on this axis without a coordinated edit on the
5143 // sibling kustomization `healthChecks[].apiVersion` (the second
5144 // render-side occurrence the same lift threads through) would
5145 // have silently routed the rendered `HelmRelease` outside the
5146 // controller's `Watches` and broken at apply time with a non-
5147 // self-locating "no kind 'HelmRelease' is registered for version
5148 // 'helm.toolkit.fluxcd.io/v2beta2'" error. Peer with
5149 // [`cluster_bundle_kustomization_uses_lifted_flux_system_namespace`]
5150 // on the sibling [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] lift.
5151 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5152 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5153 let hr = files
5154 .iter()
5155 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
5156 .expect("helmrelease.yaml present");
5157 let parsed: serde_yaml::Value =
5158 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
5159 assert_eq!(
5160 kube_root_str_field(&parsed, KUBE_KEY_API_VERSION),
5161 Some(FLUX_HELMRELEASE_API_VERSION),
5162 "helmrelease.yaml apiVersion must spell the lifted \
5163 FLUX_HELMRELEASE_API_VERSION ({FLUX_HELMRELEASE_API_VERSION:?}); \
5164 a drifted literal here routes the HelmRelease outside the Flux v2 \
5165 helm-controller's Watches",
5166 );
5167 }
5168
5169 #[test]
5170 fn cluster_bundle_kustomization_health_check_uses_lifted_flux_api_version() {
5171 // Sibling-axis pin to
5172 // `cluster_bundle_helmrelease_uses_lifted_flux_api_version`: the
5173 // rendered `kustomization.yaml`'s `spec.healthChecks[].apiVersion`
5174 // axis is the Flux v2 contract pairing the parent Kustomization's
5175 // per-resource health-gate to the sibling HelmRelease's CRD
5176 // group/version. Both axes must resolve to the same lifted
5177 // constant by value — a future upstream Flux v3 migration on
5178 // either axis without a coordinated edit on the other would
5179 // have silently dangled the health-check (apply-side: the per-
5180 // resource health-gate never resolves, the parent Kustomization
5181 // sits perpetually in `Reconciling`).
5182 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5183 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5184 let kust = files
5185 .iter()
5186 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
5187 .expect("kustomization.yaml present");
5188 let parsed: serde_yaml::Value =
5189 serde_yaml::from_str(&kust.contents).expect("kustomization.yaml parses as YAML");
5190 let health_checks = parsed
5191 .get(KUBE_KEY_SPEC)
5192 .and_then(|s| s.get(FLUX_KEY_HEALTH_CHECKS))
5193 .and_then(|h| h.as_sequence())
5194 .expect("kustomization.yaml spec.healthChecks present");
5195 assert!(
5196 !health_checks.is_empty(),
5197 "kustomization.yaml spec.healthChecks must carry at least one \
5198 entry — the rendered Kustomization gates on its sibling \
5199 HelmRelease's health by construction",
5200 );
5201 for (i, entry) in health_checks.iter().enumerate() {
5202 assert_eq!(
5203 kube_root_str_field(entry, KUBE_KEY_API_VERSION),
5204 Some(FLUX_HELMRELEASE_API_VERSION),
5205 "kustomization.yaml spec.healthChecks[{i}].apiVersion must \
5206 spell the lifted FLUX_HELMRELEASE_API_VERSION \
5207 ({FLUX_HELMRELEASE_API_VERSION:?}); a drifted literal here \
5208 dangles the per-resource health-gate at apply time",
5209 );
5210 }
5211 }
5212
5213 #[test]
5214 fn cluster_bundle_helmrelease_pins_canonical_flux_v2_api_version_string() {
5215 // Bridge-arm pin: the lifted [`FLUX_HELMRELEASE_API_VERSION`]
5216 // constant resolves to the canonical
5217 // `"helm.toolkit.fluxcd.io/v2"` string today, and both rendered
5218 // axes (helmrelease.yaml apiVersion + kustomization.yaml
5219 // healthChecks[].apiVersion) must spell it out verbatim. Pin the
5220 // literal here (peer with the
5221 // [`flux_helmrelease_api_version_pins_canonical_value`] canonical-
5222 // default arm in caixa-core, and with
5223 // [`cluster_bundle_kustomization_pins_canonical_flux_system_string`]
5224 // on the sibling `DEFAULT_FLUX_SYSTEM_NAMESPACE` axis) so a
5225 // future Flux v3 migration of the lifted constant surfaces here
5226 // as a coordinated edit-point.
5227 assert_eq!(FLUX_HELMRELEASE_API_VERSION, "helm.toolkit.fluxcd.io/v2");
5228 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5229 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5230 let hr = files
5231 .iter()
5232 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
5233 .unwrap();
5234 assert!(
5235 hr.contents
5236 .contains("apiVersion: helm.toolkit.fluxcd.io/v2\n"),
5237 "helmrelease.yaml must spell the canonical Flux v2 HelmRelease \
5238 apiVersion at the top-level apiVersion axis (got: {contents:?})",
5239 contents = hr.contents,
5240 );
5241 let kust = files
5242 .iter()
5243 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
5244 .unwrap();
5245 assert!(
5246 kust.contents
5247 .contains("apiVersion: helm.toolkit.fluxcd.io/v2\n"),
5248 "kustomization.yaml must spell the canonical Flux v2 HelmRelease \
5249 apiVersion at spec.healthChecks[].apiVersion (got: {contents:?})",
5250 contents = kust.contents,
5251 );
5252 }
5253
5254 #[test]
5255 fn cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix() {
5256 // Fail-before-pass-after pin: the [`ClusterBundleOpts::for_caixa`]
5257 // constructor's default `git_ref: GitRefSpec::Tag(...)` must
5258 // compose the lifted [`caixa_core::DEFAULT_PUBLISH_TAG_PREFIX`]
5259 // against the caixa's `:versao` — not an inline `"v"` byte the
5260 // peer `feira publish` `--prefix` default and this deploy-side
5261 // default could silently drift on.
5262 //
5263 // Until this lift landed the deploy-side carried a `format!("v{}",
5264 // caixa.versao)` literal while the writer-side (caixa-feira/src/cmd/publish.rs:22)
5265 // carried a clap `default_value = "v"` literal — two production-code
5266 // consumers of the same git-tag-naming convention on the same
5267 // git remote axis, drift-prone by construction. A future
5268 // Zig-style-tag rebrand on one side (e.g. moving the publisher to
5269 // `release/<versao>` once a sibling forge convention lands)
5270 // without a coordinated edit here would silently emit a tag the
5271 // FluxCD `GitRepository` reconciler can't resolve — the
5272 // dependent `HelmRelease`'s `chart: sourceRef` would never
5273 // converge and every per-Servico apply would silently come up
5274 // with the prior reconciled state, with the failure surfacing
5275 // far from the rebrand commit's source at
5276 // `kubectl describe gitrepository` time.
5277 //
5278 // Pin the equality on the constructed `GitRefSpec::Tag` body and
5279 // on the rendered `gitrepository.yaml`'s `ref: { tag: ... }`
5280 // field so a regression that re-inlines the `"v"` literal at
5281 // either layer (this constructor or the format-string in
5282 // [`cluster_bundle`]) surfaces here as a build-time test failure
5283 // rather than as a silent deploy-time `GitRepository` reconcile
5284 // loop. Peer to the sibling [`caixa-feira`]
5285 // `publish_prefix_default_pins_lifted_caixa_core_constant` test
5286 // closing the same drift on the writer-side.
5287 let caixa = sample_caixa();
5288 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
5289 match &opts.git_ref {
5290 GitRefSpec::Tag(tag) => {
5291 assert!(
5292 tag.starts_with(caixa_core::DEFAULT_PUBLISH_TAG_PREFIX),
5293 "default git_ref tag must start with the lifted \
5294 caixa_core::DEFAULT_PUBLISH_TAG_PREFIX (got: {tag:?})"
5295 );
5296 assert_eq!(
5297 tag,
5298 &format!(
5299 "{prefix}{versao}",
5300 prefix = caixa_core::DEFAULT_PUBLISH_TAG_PREFIX,
5301 versao = caixa.versao(),
5302 ),
5303 "default git_ref tag must compose the lifted prefix \
5304 against the caixa's :versao verbatim"
5305 );
5306 }
5307 other => panic!("expected GitRefSpec::Tag, got {other:?}"),
5308 }
5309 let files = cluster_bundle(&caixa, &opts).unwrap();
5310 let gr = files
5311 .iter()
5312 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
5313 .expect("gitrepository.yaml present");
5314 let expected_tag = format!(
5315 "{prefix}{versao}",
5316 prefix = caixa_core::DEFAULT_PUBLISH_TAG_PREFIX,
5317 versao = caixa.versao(),
5318 );
5319 assert!(
5320 gr.contents.contains(&format!("tag: {expected_tag:?}")),
5321 "gitrepository.yaml must spell the lifted-prefix-composed tag \
5322 at ref.tag (expected: {expected_tag:?}, got: {contents:?})",
5323 contents = gr.contents
5324 );
5325 }
5326
5327 #[test]
5328 fn cluster_bundle_default_git_tag_versao_routes_through_caixa_versao_accessor() {
5329 // Emit-path pin: the per-`ClusterBundleOpts::for_caixa`
5330 // constructor's default `git_ref: GitRefSpec::Tag(...)` body
5331 // and the paired `gitrepository.yaml`'s `ref.tag` scalar must
5332 // derive their terminal `{versao}` byte-string through the
5333 // typed [`caixa_core::Caixa::versao`] accessor byte-for-byte.
5334 // Before this converge the emit site carried a raw
5335 // `caixa.versao` `Display` field-access into the
5336 // `format!("{prefix}{versao}", ...)` template, bypassing the
5337 // typed dispatch. Sibling of the 05a7701 (caixa-helm)
5338 // `Caixa::versao` Display-axis converge — this closes the
5339 // co-resident `Caixa::versao` Display-axis in caixa-flux the
5340 // sibling 4a363bf `Caixa::nome` `String`-carry axis and
5341 // 162e2e2 `Caixa::nome` `&str`/Display-axis converges in
5342 // this crate already closed on the peer `Caixa::nome`
5343 // primitive, so caixa-flux now owns every projection of the
5344 // `Caixa::versao` axis through the typed accessor.
5345 //
5346 // A future extension of the accessor (a SemVer-2
5347 // build-metadata canonicalization pass, an OCI-tag
5348 // normalization the M4 registry-alignment slot lands, a
5349 // per-edition pre-release-tag overlay dispatched through
5350 // `Caixa::edicao`) that landed on the accessor but not on
5351 // this emit site would silently split the FluxCD
5352 // `GitRepository` clone-target `ref.tag` from every other
5353 // per-Caixa version-identity consumer (the peer caixa-helm
5354 // Chart.yaml `version:` / `appVersion:` and README `Origin`
5355 // line, the paired `feira publish` git-tag `v{versao}`
5356 // emit) — the source-controller would then resolve a
5357 // pre-extension git tag while the paired `HelmRelease` /
5358 // Chart.yaml / README carried the post-extension form,
5359 // silently freezing every deployed chart at the wrong
5360 // per-caixa git snapshot. Pin the equality on the
5361 // constructed `GitRefSpec::Tag` body and on the rendered
5362 // `gitrepository.yaml`'s `ref: { tag: ... }` field so a
5363 // regression that re-inlines the raw `caixa.versao` field
5364 // access at either layer (this constructor or the
5365 // format-string in [`cluster_bundle`]) surfaces here as a
5366 // build-time test failure rather than as a silent
5367 // deploy-time `GitRepository` reconcile loop.
5368 let caixa = sample_caixa();
5369 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
5370 let expected_tag = format!(
5371 "{prefix}{versao}",
5372 prefix = caixa_core::DEFAULT_PUBLISH_TAG_PREFIX,
5373 versao = caixa.versao(),
5374 );
5375 match &opts.git_ref {
5376 GitRefSpec::Tag(tag) => assert_eq!(
5377 tag, &expected_tag,
5378 "default git_ref tag must derive its `{{versao}}` \
5379 scalar through the typed `caixa_core::Caixa::versao` \
5380 accessor — a regression that re-inlines \
5381 `caixa.versao` at the constructor site silently \
5382 splits the FluxCD `GitRepository` clone-target \
5383 `ref.tag` from every other per-Caixa \
5384 version-identity consumer"
5385 ),
5386 other => panic!("expected GitRefSpec::Tag, got {other:?}"),
5387 }
5388 let files = cluster_bundle(&caixa, &opts).unwrap();
5389 let gr = files
5390 .iter()
5391 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
5392 .expect("gitrepository.yaml present");
5393 assert!(
5394 gr.contents.contains(&format!("tag: {expected_tag:?}")),
5395 "gitrepository.yaml must spell the accessor-derived tag \
5396 at ref.tag (expected: {expected_tag:?}, got: {contents:?}) \
5397 — a regression that re-inlines `caixa.versao` at the \
5398 [`cluster_bundle`] format-string site silently splits \
5399 the on-disk Flux v2 `GitRepository` YAML from the \
5400 substrate's per-caixa version-identity dispatch",
5401 contents = gr.contents
5402 );
5403 }
5404
5405 #[test]
5406 fn flux_gitrepository_api_version_re_export_points_at_caixa_core_canonical() {
5407 // The renderer's `pub use caixa_core::FLUX_GITREPOSITORY_API_VERSION`
5408 // is the single source of truth for the Flux v2 `GitRepository`
5409 // CRD-group/version the rendered `gitrepository.yaml` document
5410 // declares at its `apiVersion` axis. Pin the equality (and the
5411 // static-data identity, peer with the sibling
5412 // `default_flux_system_namespace_re_export_points_at_caixa_core_canonical` /
5413 // `default_library_name_re_export_points_at_caixa_core_canonical`
5414 // pins) so any local re-introduction of a sibling `pub const
5415 // FLUX_GITREPOSITORY_API_VERSION: &str = "…"` (the canonical drift
5416 // footgun this lift closes — one production-code consumer of the
5417 // load-bearing Flux v2 `GitRepository` CRD-group/version inside
5418 // the gitrepository template, lifted to one re-export at the
5419 // caixa-core boundary) is a build-time test failure naming the
5420 // offending drift, not a silent apply-time `GitRepository`-
5421 // outside-controller-watch-window reconciliation freeze.
5422 caixa_core::assert_str_reexport_identity(
5423 "FLUX_GITREPOSITORY_API_VERSION",
5424 FLUX_GITREPOSITORY_API_VERSION,
5425 caixa_core::FLUX_GITREPOSITORY_API_VERSION,
5426 );
5427 }
5428
5429 #[test]
5430 fn cluster_bundle_gitrepository_uses_lifted_flux_api_version() {
5431 // Fail-before-pass-after pin: the rendered `gitrepository.yaml`
5432 // `apiVersion` axis — the load-bearing Flux v2 CRD-group/version
5433 // declaration the `source-controller` watches — must resolve to the
5434 // lifted [`FLUX_GITREPOSITORY_API_VERSION`] verbatim. Before this
5435 // lift the gitrepository template carried an inline
5436 // `source.toolkit.fluxcd.io/v1` literal; a future upstream Flux v3
5437 // migration on this axis without a coordinated edit on the sibling
5438 // [`FLUX_HELMRELEASE_API_VERSION`] axis (the Flux v2 controller-
5439 // triple shares the `.toolkit.fluxcd.io` root and promotes together
5440 // on each major bump) would have silently routed the rendered
5441 // `GitRepository` outside the controller's `Watches` and broken at
5442 // apply time with a non-self-locating "no kind 'GitRepository' is
5443 // registered for version 'source.toolkit.fluxcd.io/v1beta2'"
5444 // error. Peer with
5445 // [`cluster_bundle_helmrelease_uses_lifted_flux_api_version`] on
5446 // the sibling [`FLUX_HELMRELEASE_API_VERSION`] lift.
5447 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5448 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5449 let gr = files
5450 .iter()
5451 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
5452 .expect("gitrepository.yaml present");
5453 let parsed: serde_yaml::Value =
5454 serde_yaml::from_str(&gr.contents).expect("gitrepository.yaml parses as YAML");
5455 assert_eq!(
5456 kube_root_str_field(&parsed, KUBE_KEY_API_VERSION),
5457 Some(FLUX_GITREPOSITORY_API_VERSION),
5458 "gitrepository.yaml apiVersion must spell the lifted \
5459 FLUX_GITREPOSITORY_API_VERSION ({FLUX_GITREPOSITORY_API_VERSION:?}); \
5460 a drifted literal here routes the GitRepository outside the Flux v2 \
5461 source-controller's Watches",
5462 );
5463 }
5464
5465 #[test]
5466 fn cluster_bundle_gitrepository_pins_canonical_flux_v1_api_version_string() {
5467 // Bridge-arm pin: the lifted [`FLUX_GITREPOSITORY_API_VERSION`]
5468 // constant resolves to the canonical
5469 // `"source.toolkit.fluxcd.io/v1"` string today, and the rendered
5470 // `gitrepository.yaml`'s `apiVersion` axis must spell it out
5471 // verbatim. Pin the literal here (peer with the
5472 // [`flux_gitrepository_api_version_pins_canonical_value`]
5473 // canonical-default arm in caixa-core, and with
5474 // [`cluster_bundle_helmrelease_pins_canonical_flux_v2_api_version_string`]
5475 // on the sibling `FLUX_HELMRELEASE_API_VERSION` axis) so a future
5476 // Flux v3 migration of the lifted constant surfaces here as a
5477 // coordinated edit-point.
5478 assert_eq!(
5479 FLUX_GITREPOSITORY_API_VERSION,
5480 "source.toolkit.fluxcd.io/v1"
5481 );
5482 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5483 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5484 let gr = files
5485 .iter()
5486 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
5487 .unwrap();
5488 assert!(
5489 gr.contents
5490 .contains("apiVersion: source.toolkit.fluxcd.io/v1\n"),
5491 "gitrepository.yaml must spell the canonical Flux v2 GitRepository \
5492 apiVersion at the top-level apiVersion axis (got: {contents:?})",
5493 contents = gr.contents,
5494 );
5495 }
5496
5497 #[test]
5498 fn flux_kustomization_api_version_re_export_points_at_caixa_core_canonical() {
5499 // The renderer's `pub use caixa_core::FLUX_KUSTOMIZATION_API_VERSION`
5500 // is the single source of truth for the Flux v2 `Kustomization`
5501 // CRD-group/version the rendered `kustomization.yaml` document
5502 // declares at its `apiVersion` axis. Pin the equality (and the
5503 // static-data identity, peer with the sibling
5504 // [`flux_gitrepository_api_version_re_export_points_at_caixa_core_canonical`]
5505 // / [`default_flux_system_namespace_re_export_points_at_caixa_core_canonical`]
5506 // pins) so any local re-introduction of a sibling `pub const
5507 // FLUX_KUSTOMIZATION_API_VERSION: &str = "…"` (the canonical drift
5508 // footgun this lift closes — one production-code consumer of the
5509 // load-bearing Flux v2 `Kustomization` CRD-group/version inside
5510 // the kustomization template, lifted to one re-export at the
5511 // caixa-core boundary) is a build-time test failure naming the
5512 // offending drift, not a silent apply-time `Kustomization`-
5513 // outside-controller-watch-window reconciliation freeze.
5514 caixa_core::assert_str_reexport_identity(
5515 "FLUX_KUSTOMIZATION_API_VERSION",
5516 FLUX_KUSTOMIZATION_API_VERSION,
5517 caixa_core::FLUX_KUSTOMIZATION_API_VERSION,
5518 );
5519 }
5520
5521 #[test]
5522 fn cluster_bundle_kustomization_uses_lifted_flux_api_version() {
5523 // Fail-before-pass-after pin: the rendered `kustomization.yaml`
5524 // top-level `apiVersion` axis — the load-bearing Flux v2
5525 // CRD-group/version declaration the `kustomize-controller`
5526 // watches — must resolve to the lifted
5527 // [`FLUX_KUSTOMIZATION_API_VERSION`] verbatim. Before this lift
5528 // the kustomization template carried an inline
5529 // `kustomize.toolkit.fluxcd.io/v1` literal; a future upstream
5530 // Flux v3 migration on this axis without a coordinated edit on
5531 // the sibling [`FLUX_HELMRELEASE_API_VERSION`] /
5532 // [`FLUX_GITREPOSITORY_API_VERSION`] axes (the Flux v2
5533 // controller triplet shares the `.toolkit.fluxcd.io` root and
5534 // promotes together on each major bump) would have silently
5535 // routed the rendered `Kustomization` outside the controller's
5536 // `Watches` and broken at apply time with a non-self-locating
5537 // "no kind 'Kustomization' is registered for version
5538 // 'kustomize.toolkit.fluxcd.io/v1beta2'" error. Peer with
5539 // [`cluster_bundle_helmrelease_uses_lifted_flux_api_version`] /
5540 // [`cluster_bundle_gitrepository_uses_lifted_flux_api_version`]
5541 // on the sibling Flux-CRD-axis lifts.
5542 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5543 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5544 let kz = files
5545 .iter()
5546 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
5547 .expect("kustomization.yaml present");
5548 let parsed: serde_yaml::Value =
5549 serde_yaml::from_str(&kz.contents).expect("kustomization.yaml parses as YAML");
5550 assert_eq!(
5551 kube_root_str_field(&parsed, KUBE_KEY_API_VERSION),
5552 Some(FLUX_KUSTOMIZATION_API_VERSION),
5553 "kustomization.yaml apiVersion must spell the lifted \
5554 FLUX_KUSTOMIZATION_API_VERSION ({FLUX_KUSTOMIZATION_API_VERSION:?}); \
5555 a drifted literal here routes the Kustomization outside the Flux v2 \
5556 kustomize-controller's Watches",
5557 );
5558 }
5559
5560 #[test]
5561 fn cluster_bundle_kustomization_pins_canonical_flux_v1_api_version_string() {
5562 // Bridge-arm pin: the lifted [`FLUX_KUSTOMIZATION_API_VERSION`]
5563 // constant resolves to the canonical
5564 // `"kustomize.toolkit.fluxcd.io/v1"` string today, and the
5565 // rendered `kustomization.yaml`'s top-level `apiVersion` axis
5566 // must spell it out verbatim. Pin the literal here (peer with
5567 // the [`flux_kustomization_api_version_pins_canonical_value`]
5568 // canonical-default arm in caixa-core, and with
5569 // [`cluster_bundle_helmrelease_pins_canonical_flux_v2_api_version_string`]
5570 // / [`cluster_bundle_gitrepository_pins_canonical_flux_v1_api_version_string`]
5571 // on the sibling `FLUX_HELMRELEASE_API_VERSION` /
5572 // `FLUX_GITREPOSITORY_API_VERSION` axes) so a future Flux v3
5573 // migration of the lifted constant surfaces here as a
5574 // coordinated edit-point.
5575 assert_eq!(
5576 FLUX_KUSTOMIZATION_API_VERSION,
5577 "kustomize.toolkit.fluxcd.io/v1"
5578 );
5579 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5580 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5581 let kz = files
5582 .iter()
5583 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
5584 .unwrap();
5585 assert!(
5586 kz.contents
5587 .contains("apiVersion: kustomize.toolkit.fluxcd.io/v1\n"),
5588 "kustomization.yaml must spell the canonical Flux v2 Kustomization \
5589 apiVersion at the top-level apiVersion axis (got: {contents:?})",
5590 contents = kz.contents,
5591 );
5592 }
5593
5594 #[test]
5595 fn cluster_bundle_every_flux_cr_carries_top_level_api_version_label_from_lifted_key() {
5596 // Fail-before-pass-after production-side sweep pin: every one of
5597 // the three rendered Flux bundle files' top-level `apiVersion:`
5598 // YAML label — the load-bearing per-CR CRD-group/version-axis
5599 // label naming the exact key the apiserver's `RESTMapper` reads
5600 // to resolve each CR's registered `CustomResourceDefinition` —
5601 // must byte-compose the lifted [`KUBE_KEY_API_VERSION`] verbatim
5602 // as its label prefix. Before this sweep the three
5603 // [`cluster_bundle`] format-string templates carried four inline
5604 // `apiVersion:` YAML label literals (gitrepository.yaml top-level
5605 // + helmrelease.yaml top-level + kustomization.yaml top-level +
5606 // kustomization.yaml `spec.healthChecks[].apiVersion`) side-by-
5607 // side with their `{api_version}`-interpolated value axes; a
5608 // future rebrand of the lifted [`KUBE_KEY_API_VERSION`] const
5609 // (or a coordinated K8s-API-conventions per-major-version
5610 // discriminator promotion) had to reach every inline label site
5611 // in lockstep, or the emit-side silently kept the pre-rebrand
5612 // label byte while the per-CR body-key retrieval sites (already
5613 // routed through [`KUBE_KEY_API_VERSION`]) rebranded — the two
5614 // sides would then disagree on the label byte, and every
5615 // downstream apiserver-side `RESTMapper` lookup on the rendered
5616 // CR would silently miss its per-CR CRD-group/version
5617 // registration with no field naming the label-drift root cause
5618 // far from the source caixa.lisp. Peer to
5619 // [`cluster_bundle_helmrelease_uses_lifted_flux_api_version`] /
5620 // [`cluster_bundle_gitrepository_uses_lifted_flux_api_version`] /
5621 // [`cluster_bundle_kustomization_uses_lifted_flux_api_version`]
5622 // on the sibling per-CR `.get(KUBE_KEY_API_VERSION)` retrieval-
5623 // side pins one level below the raw-byte label-axis this pin
5624 // gates.
5625 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5626 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5627 let label_prefix = format!("{KUBE_KEY_API_VERSION}: ");
5628 for filename in [
5629 FLUX_GITREPOSITORY_YAML_FILENAME,
5630 FLUX_HELMRELEASE_YAML_FILENAME,
5631 FLUX_KUSTOMIZATION_YAML_FILENAME,
5632 ] {
5633 let f = files
5634 .iter()
5635 .find(|f| f.path == std::path::PathBuf::from(filename))
5636 .unwrap_or_else(|| panic!("{filename} present"));
5637 assert!(
5638 f.contents.contains(&label_prefix),
5639 "{filename} must carry the top-level {label_prefix:?} YAML label \
5640 composed from the lifted KUBE_KEY_API_VERSION ({KUBE_KEY_API_VERSION:?}); \
5641 a drifted inline label here silently rebrands the per-CR \
5642 CRD-group/version-axis discriminator away from the lifted key \
5643 (got: {contents:?})",
5644 contents = f.contents,
5645 );
5646 }
5647 }
5648
5649 #[test]
5650 fn cluster_bundle_every_flux_cr_carries_top_level_kind_label_from_lifted_key() {
5651 // Fail-before-pass-after production-side sweep pin: every one of
5652 // the three rendered Flux bundle files' top-level `kind:` YAML
5653 // label — the load-bearing per-CR CRD-`kind`-discriminator-axis
5654 // label naming the exact key the apiserver's `RESTMapper` reads
5655 // to resolve each CR's registered `CustomResourceDefinition`
5656 // against the sibling `apiVersion:` half of the `(apiVersion,
5657 // kind)` CRD-lookup tuple — must byte-compose the lifted
5658 // [`KUBE_KEY_KIND`] verbatim as its label prefix. Before this
5659 // sweep the three [`cluster_bundle`] format-string templates
5660 // carried six inline `kind:` YAML label literals
5661 // (gitrepository.yaml top-level + helmrelease.yaml top-level +
5662 // helmrelease.yaml `spec.chart.spec.sourceRef.kind` +
5663 // kustomization.yaml top-level + kustomization.yaml
5664 // `spec.sourceRef.kind` + kustomization.yaml
5665 // `spec.healthChecks[].kind`) side-by-side with their
5666 // `{kind}` / `{source_kind}` / `{health_kind}`-interpolated
5667 // value axes; a future rebrand of the lifted [`KUBE_KEY_KIND`]
5668 // const (or a coordinated K8s-API-conventions per-major-version
5669 // discriminator promotion) had to reach every inline label site
5670 // in lockstep, or the emit-side silently kept the pre-rebrand
5671 // label byte while the per-CR body-key retrieval sites (already
5672 // routed through [`KUBE_KEY_KIND`] via `kube_root_str_field` /
5673 // `kube_kind_is`) rebranded — the two sides would then disagree
5674 // on the label byte, and every downstream apiserver-side
5675 // `RESTMapper` / Flux-controller-side `Watches` predicate on the
5676 // rendered CR would silently miss its per-CR CRD-`kind` match
5677 // with no field naming the label-drift root cause far from the
5678 // source caixa.lisp. Peer to
5679 // [`cluster_bundle_every_flux_cr_carries_top_level_api_version_label_from_lifted_key`]
5680 // on the sibling apiVersion half of the same `(apiVersion, kind)`
5681 // CRD-lookup tuple — extends the production-side raw-byte-label-
5682 // sweep discipline established there onto the sibling
5683 // discriminator-half's raw-byte label position, so the two
5684 // halves of the tuple's label axes both consume the same
5685 // substrate-owned `&'static str` by construction.
5686 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5687 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5688 let label_prefix = format!("{KUBE_KEY_KIND}: ");
5689 for filename in [
5690 FLUX_GITREPOSITORY_YAML_FILENAME,
5691 FLUX_HELMRELEASE_YAML_FILENAME,
5692 FLUX_KUSTOMIZATION_YAML_FILENAME,
5693 ] {
5694 let f = files
5695 .iter()
5696 .find(|f| f.path == std::path::PathBuf::from(filename))
5697 .unwrap_or_else(|| panic!("{filename} present"));
5698 assert!(
5699 f.contents.contains(&label_prefix),
5700 "{filename} must carry the top-level {label_prefix:?} YAML label \
5701 composed from the lifted KUBE_KEY_KIND ({KUBE_KEY_KIND:?}); \
5702 a drifted inline label here silently rebrands the per-CR \
5703 CRD-`kind`-discriminator-axis away from the lifted key \
5704 (got: {contents:?})",
5705 contents = f.contents,
5706 );
5707 }
5708 }
5709
5710 #[test]
5711 fn cluster_bundle_every_flux_cr_carries_top_level_metadata_label_from_lifted_key() {
5712 // Fail-before-pass-after production-side sweep pin: every one of
5713 // the three rendered Flux bundle files' top-level `metadata:`
5714 // YAML label — the load-bearing per-CR block-scope key naming
5715 // the exact axis the apiserver reads to resolve each CR's
5716 // ObjectMeta (`.metadata.name` / `.metadata.namespace` /
5717 // `.metadata.labels` / `.metadata.annotations`) against the
5718 // sibling `spec:` half of the top-level `(metadata, spec)`
5719 // K8s-CR-shape pair — must byte-compose the lifted
5720 // [`KUBE_KEY_METADATA`] verbatim as its label prefix. Before
5721 // this sweep the three [`cluster_bundle`] format-string
5722 // templates carried three inline `metadata:` YAML label
5723 // literals (gitrepository.yaml top-level +
5724 // helmrelease.yaml top-level + kustomization.yaml top-level)
5725 // side-by-side with their `name: {name}` / `namespace:
5726 // {namespace}` children; a future rebrand of the lifted
5727 // [`KUBE_KEY_METADATA`] const (or a coordinated
5728 // K8s-API-conventions per-major-version ObjectMeta-block-key
5729 // promotion) had to reach every inline label site in lockstep,
5730 // or the emit-side silently kept the pre-rebrand label byte
5731 // while the per-CR body-key retrieval sites (already routed
5732 // through [`KUBE_KEY_METADATA`] via `kube_metadata_str_field`)
5733 // rebranded — the two sides would then disagree on the label
5734 // byte, and every downstream apiserver-side ObjectMeta parser
5735 // on the rendered CR would silently miss its per-CR
5736 // `metadata.name` / `metadata.namespace` lookup with no field
5737 // naming the label-drift root cause far from the source
5738 // caixa.lisp. Peer to
5739 // [`cluster_bundle_every_flux_cr_carries_top_level_kind_label_from_lifted_key`]
5740 // (ef2c7ef) /
5741 // [`cluster_bundle_every_flux_cr_carries_top_level_api_version_label_from_lifted_key`]
5742 // (6d3cbf0) on the sibling `kind:` / `apiVersion:` halves of
5743 // the same top-level K8s-CR shape — extends the production-
5744 // side raw-byte-label-sweep discipline established there onto
5745 // the sibling ObjectMeta-block-scope label position, so the
5746 // three top-level K8s-CR body-block label axes all consume
5747 // the same substrate-owned `&'static str`s by construction.
5748 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5749 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5750 let label_prefix = format!("{KUBE_KEY_METADATA}:");
5751 for filename in [
5752 FLUX_GITREPOSITORY_YAML_FILENAME,
5753 FLUX_HELMRELEASE_YAML_FILENAME,
5754 FLUX_KUSTOMIZATION_YAML_FILENAME,
5755 ] {
5756 let f = files
5757 .iter()
5758 .find(|f| f.path == std::path::PathBuf::from(filename))
5759 .unwrap_or_else(|| panic!("{filename} present"));
5760 assert!(
5761 f.contents.contains(&label_prefix),
5762 "{filename} must carry the top-level {label_prefix:?} YAML label \
5763 composed from the lifted KUBE_KEY_METADATA ({KUBE_KEY_METADATA:?}); \
5764 a drifted inline label here silently rebrands the per-CR \
5765 ObjectMeta-block-scope axis away from the lifted key \
5766 (got: {contents:?})",
5767 contents = f.contents,
5768 );
5769 }
5770 }
5771
5772 #[test]
5773 fn cluster_bundle_every_flux_cr_carries_top_level_spec_label_from_lifted_key() {
5774 // Fail-before-pass-after production-side sweep pin: every one of
5775 // the three rendered Flux bundle files' top-level `spec:` YAML
5776 // label — the load-bearing per-CR block-scope key naming the
5777 // exact axis the apiserver reads to resolve each CR's payload
5778 // (`.spec.interval` / `.spec.url` / `.spec.chart.spec.*` /
5779 // `.spec.sourceRef` / `.spec.path` / `.spec.healthChecks` /
5780 // `.spec.timeout` / `.spec.install` / `.spec.upgrade` /
5781 // `.spec.values` / `.spec.prune`) against the sibling
5782 // `metadata:` half of the top-level `(metadata, spec)` K8s-CR-
5783 // shape pair — must byte-compose the lifted [`KUBE_KEY_SPEC`]
5784 // verbatim as its label prefix. Before this sweep the three
5785 // [`cluster_bundle`] format-string templates carried four inline
5786 // `spec:` YAML label literals (gitrepository.yaml top-level +
5787 // helmrelease.yaml top-level + helmrelease.yaml
5788 // `spec.chart.spec` nested + kustomization.yaml top-level)
5789 // side-by-side with their per-CR `interval:` / `url:` /
5790 // `chart:` / `sourceRef:` / `install:` / `upgrade:` / `values:`
5791 // / `path:` / `healthChecks:` / `timeout:` children; a future
5792 // rebrand of the lifted [`KUBE_KEY_SPEC`] const (or a
5793 // coordinated K8s-API-conventions per-major-version body-block-
5794 // key promotion) had to reach every inline label site in
5795 // lockstep, or the emit-side silently kept the pre-rebrand
5796 // label byte while the retrieval-side per-CR body-key readers
5797 // (already routed through [`KUBE_KEY_SPEC`] via caixa-core's
5798 // `servico_spec_and_m2_overlay_entries` / caixa-flux's
5799 // `programs_yaml_entry` / caixa-mesh's per-CNP/HTTPRoute walks)
5800 // rebranded — the two sides would then disagree on the label
5801 // byte, and every downstream apiserver-side spec-block parser
5802 // on the rendered CR would silently miss its per-CR
5803 // `spec.interval` / `spec.url` / `spec.chart` / `spec.sourceRef`
5804 // / `spec.install` / `spec.upgrade` / `spec.values` /
5805 // `spec.path` / `spec.healthChecks` / `spec.timeout` lookup
5806 // with no field naming the label-drift root cause far from the
5807 // source caixa.lisp. Peer to
5808 // [`cluster_bundle_every_flux_cr_carries_top_level_metadata_label_from_lifted_key`]
5809 // (83ce571) /
5810 // [`cluster_bundle_every_flux_cr_carries_top_level_kind_label_from_lifted_key`]
5811 // (ef2c7ef) /
5812 // [`cluster_bundle_every_flux_cr_carries_top_level_api_version_label_from_lifted_key`]
5813 // (6d3cbf0) on the sibling `metadata:` / `kind:` / `apiVersion:`
5814 // halves of the same top-level K8s-CR shape — closes the
5815 // fourth (and final) canonical K8s-CR top-level block-scope
5816 // label axis under the same production-side raw-byte-label-
5817 // sweep discipline the prior three commits established, so
5818 // every top-level K8s-CR body-block label position across the
5819 // whole `cluster_bundle` render surface consumes the same
5820 // substrate-owned `&'static str`s by construction.
5821 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5822 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5823 let label_prefix = format!("{KUBE_KEY_SPEC}:");
5824 for filename in [
5825 FLUX_GITREPOSITORY_YAML_FILENAME,
5826 FLUX_HELMRELEASE_YAML_FILENAME,
5827 FLUX_KUSTOMIZATION_YAML_FILENAME,
5828 ] {
5829 let f = files
5830 .iter()
5831 .find(|f| f.path == std::path::PathBuf::from(filename))
5832 .unwrap_or_else(|| panic!("{filename} present"));
5833 assert!(
5834 f.contents.contains(&label_prefix),
5835 "{filename} must carry the top-level {label_prefix:?} YAML label \
5836 composed from the lifted KUBE_KEY_SPEC ({KUBE_KEY_SPEC:?}); \
5837 a drifted inline label here silently rebrands the per-CR \
5838 spec-block-scope axis away from the lifted key \
5839 (got: {contents:?})",
5840 contents = f.contents,
5841 );
5842 }
5843 }
5844
5845 #[test]
5846 fn cluster_bundle_every_flux_cr_carries_metadata_namespace_label_from_lifted_key() {
5847 // Fail-before-pass-after production-side sweep pin: every one
5848 // of the three rendered Flux bundle files' `namespace:` YAML
5849 // label positions — the load-bearing per-CR-`metadata.namespace`
5850 // axis the apiserver reads to route each CR into its target
5851 // namespace (`gitrepository.yaml` top-level +
5852 // `helmrelease.yaml` top-level + `helmrelease.yaml`
5853 // `spec.chart.spec.sourceRef.namespace` nested + `kustomization.yaml`
5854 // top-level + `kustomization.yaml`
5855 // `spec.healthChecks[].namespace` nested) against the sibling
5856 // `name:` half of the ObjectMeta / sourceRef / healthCheck
5857 // `(name, namespace)` identity-pair — must byte-compose the
5858 // lifted [`KUBE_KEY_NAMESPACE`] verbatim as its label prefix.
5859 // Before this sweep the three [`cluster_bundle`] format-string
5860 // templates carried five inline `namespace:` YAML label
5861 // literals side-by-side with the sibling per-CR `name:` half
5862 // of every `(name, namespace)` identity-pair emission; a
5863 // future rebrand of the lifted [`KUBE_KEY_NAMESPACE`] const
5864 // (or a coordinated K8s-API-conventions per-major-version
5865 // ObjectMeta-key promotion) had to reach every inline label
5866 // site in lockstep, or the emit-side silently kept the pre-
5867 // rebrand label byte while the retrieval-side per-CR
5868 // `metadata.namespace` readers (already routed through
5869 // [`KUBE_KEY_NAMESPACE`] via caixa-core's
5870 // `kube_metadata_str_field` walks + this crate's
5871 // `programs_yaml_entry` upstream ComputeUnit YAML retrieval +
5872 // `cluster_bundle`'s rendered `kustomization.yaml` drift-
5873 // detection pin) rebranded — the two sides would then
5874 // disagree on the label byte, and every downstream apiserver-
5875 // side ObjectMeta parser on the rendered CR would silently
5876 // miss its per-CR `metadata.namespace` lookup and route the
5877 // resource into `default` (or whatever fallback the calling
5878 // controller supplies) with no field naming the label-drift
5879 // root cause far from the source caixa.lisp. Peer to
5880 // [`cluster_bundle_every_flux_cr_carries_top_level_metadata_label_from_lifted_key`]
5881 // (83ce571) /
5882 // [`cluster_bundle_every_flux_cr_carries_top_level_kind_label_from_lifted_key`]
5883 // (ef2c7ef) /
5884 // [`cluster_bundle_every_flux_cr_carries_top_level_api_version_label_from_lifted_key`]
5885 // (6d3cbf0) /
5886 // [`cluster_bundle_every_flux_cr_carries_top_level_spec_label_from_lifted_key`]
5887 // (ed23a31) on the sibling `metadata:` / `kind:` /
5888 // `apiVersion:` / `spec:` halves of the top-level K8s-CR
5889 // shape — extends the same production-side raw-byte-label-
5890 // sweep discipline onto the canonical `metadata.namespace`
5891 // nested axis every rendered Flux v2 bundle document
5892 // navigates, so every `namespace:` label position across the
5893 // whole `cluster_bundle` render surface consumes the same
5894 // substrate-owned `&'static str` by construction.
5895 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5896 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5897 let label_prefix = format!("{KUBE_KEY_NAMESPACE}:");
5898 for filename in [
5899 FLUX_GITREPOSITORY_YAML_FILENAME,
5900 FLUX_HELMRELEASE_YAML_FILENAME,
5901 FLUX_KUSTOMIZATION_YAML_FILENAME,
5902 ] {
5903 let f = files
5904 .iter()
5905 .find(|f| f.path == std::path::PathBuf::from(filename))
5906 .unwrap_or_else(|| panic!("{filename} present"));
5907 assert!(
5908 f.contents.contains(&label_prefix),
5909 "{filename} must carry the {label_prefix:?} YAML label \
5910 composed from the lifted KUBE_KEY_NAMESPACE ({KUBE_KEY_NAMESPACE:?}); \
5911 a drifted inline label here silently rebrands the per-CR \
5912 metadata.namespace axis away from the lifted key \
5913 (got: {contents:?})",
5914 contents = f.contents,
5915 );
5916 }
5917 }
5918
5919 #[test]
5920 fn cluster_bundle_every_flux_cr_carries_metadata_name_label_from_lifted_key() {
5921 // Fail-before-pass-after production-side sweep pin: every one
5922 // of the three rendered Flux bundle files' `name:` YAML label
5923 // positions — the load-bearing per-CR-`metadata.name` axis the
5924 // apiserver-side ObjectMeta parser keys each rendered CR off
5925 // (`gitrepository.yaml` top-level +
5926 // `helmrelease.yaml` top-level +
5927 // `helmrelease.yaml` `spec.chart.spec.sourceRef.name` nested +
5928 // `kustomization.yaml` top-level +
5929 // `kustomization.yaml` `spec.sourceRef.name` nested +
5930 // `kustomization.yaml` `spec.healthChecks[].name` nested)
5931 // against the sibling `namespace:` half of the ObjectMeta /
5932 // sourceRef / healthCheck `(name, namespace)` identity-pair —
5933 // must byte-compose the lifted [`KUBE_KEY_NAME`] verbatim as
5934 // its label prefix. Before this sweep the three
5935 // [`cluster_bundle`] format-string templates carried six
5936 // inline `name:` YAML label literals side-by-side with the
5937 // sibling per-CR `namespace:` half of every `(name,
5938 // namespace)` identity-pair emission; a future rebrand of the
5939 // lifted [`KUBE_KEY_NAME`] const (or a coordinated K8s-API-
5940 // conventions per-major-version ObjectMeta-key promotion) had
5941 // to reach every inline label site in lockstep, or the emit-
5942 // side silently kept the pre-rebrand label byte while the
5943 // retrieval-side per-CR `metadata.name` readers (already
5944 // routed through [`KUBE_KEY_NAME`] via caixa-core's
5945 // `kube_metadata_str_field` walks + this crate's
5946 // `programs_yaml_entry` upstream ComputeUnit YAML retrieval)
5947 // rebranded — the two sides would then disagree on the label
5948 // byte, and every downstream apiserver-side ObjectMeta parser
5949 // on the rendered CR would treat the document as an anonymous
5950 // CR (or the apiserver would reject the apply with a schema-
5951 // validation error naming the wrong key) with no field naming
5952 // the label-drift root cause far from the source caixa.lisp.
5953 // Peer to
5954 // [`cluster_bundle_every_flux_cr_carries_metadata_namespace_label_from_lifted_key`]
5955 // (743e5cd) on the sibling `namespace:` half of the
5956 // ObjectMeta / sourceRef / healthCheck `(name, namespace)`
5957 // identity-pair — extends the same production-side raw-byte-
5958 // label-sweep discipline onto the paired `metadata.name`
5959 // nested axis every rendered Flux v2 bundle document
5960 // navigates, so every `name:` label position across the whole
5961 // `cluster_bundle` render surface consumes the same
5962 // substrate-owned `&'static str` by construction.
5963 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
5964 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
5965 let label_prefix = format!("{KUBE_KEY_NAME}:");
5966 for filename in [
5967 FLUX_GITREPOSITORY_YAML_FILENAME,
5968 FLUX_HELMRELEASE_YAML_FILENAME,
5969 FLUX_KUSTOMIZATION_YAML_FILENAME,
5970 ] {
5971 let f = files
5972 .iter()
5973 .find(|f| f.path == std::path::PathBuf::from(filename))
5974 .unwrap_or_else(|| panic!("{filename} present"));
5975 assert!(
5976 f.contents.contains(&label_prefix),
5977 "{filename} must carry the {label_prefix:?} YAML label \
5978 composed from the lifted KUBE_KEY_NAME ({KUBE_KEY_NAME:?}); \
5979 a drifted inline label here silently rebrands the per-CR \
5980 metadata.name axis away from the lifted key \
5981 (got: {contents:?})",
5982 contents = f.contents,
5983 );
5984 }
5985 }
5986
5987 #[test]
5988 fn flux_kind_git_repository_re_export_points_at_caixa_core_canonical() {
5989 // The renderer's `pub use caixa_core::FLUX_KIND_GIT_REPOSITORY` is
5990 // the single source of truth for the Flux v2 `GitRepository` CRD
5991 // `kind` discriminator the rendered Flux bundle's three
5992 // `GitRepository`-naming axes declare (the `gitrepository.yaml`
5993 // top-level `kind`, the `helmrelease.yaml`
5994 // `spec.chart.spec.sourceRef.kind`, and the `kustomization.yaml`
5995 // `spec.sourceRef.kind`). Pin the equality (and the static-data
5996 // identity, peer with the sibling
5997 // [`flux_gitrepository_api_version_re_export_points_at_caixa_core_canonical`]
5998 // / [`flux_kustomization_api_version_re_export_points_at_caixa_core_canonical`]
5999 // pins) so any local re-introduction of a sibling `pub const
6000 // FLUX_KIND_GIT_REPOSITORY: &str = "…"` (the canonical drift
6001 // footgun this lift closes — three production-code consumers of
6002 // the load-bearing Flux v2 `GitRepository` CRD `kind`
6003 // discriminator inside the cluster_bundle templates, lifted to one
6004 // re-export at the caixa-core boundary) is a build-time test
6005 // failure naming the offending drift, not a silent apply-time
6006 // `helm-controller` chart-resolution dangle.
6007 caixa_core::assert_str_reexport_identity(
6008 "FLUX_KIND_GIT_REPOSITORY",
6009 FLUX_KIND_GIT_REPOSITORY,
6010 caixa_core::FLUX_KIND_GIT_REPOSITORY,
6011 );
6012 }
6013
6014 #[test]
6015 fn cluster_bundle_gitrepository_kind_uses_lifted_flux_kind_git_repository() {
6016 // Fail-before-pass-after pin: the rendered `gitrepository.yaml`
6017 // top-level `kind` axis — the load-bearing K8s CRD discriminator
6018 // the Flux v2 `source-controller` resolves the rendered document
6019 // against — must resolve to the lifted
6020 // [`FLUX_KIND_GIT_REPOSITORY`] verbatim. Before this lift the
6021 // gitrepository template carried an inline `GitRepository`
6022 // literal at one of three sibling production-code call sites
6023 // across the cluster_bundle templates; the apiserver-side CRD
6024 // resolution contract is the `(apiVersion, kind)` tuple keyed
6025 // against the registered `CustomResourceDefinition`, so drift on
6026 // the kind axis is exactly as load-bearing as drift on the
6027 // sibling [`FLUX_GITREPOSITORY_API_VERSION`] axis (a future Flux
6028 // v3 rebrand on this axis without a coordinated edit on the
6029 // sibling sourceRef.kind axes silently lands the rendered
6030 // `GitRepository` outside the source-controller's `Watches`).
6031 // Peer with [`cluster_bundle_gitrepository_uses_lifted_flux_api_version`]
6032 // on the sibling apiVersion half of the same CRD-lookup tuple.
6033 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6034 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6035 let gr = files
6036 .iter()
6037 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
6038 .expect("gitrepository.yaml present");
6039 let parsed: serde_yaml::Value =
6040 serde_yaml::from_str(&gr.contents).expect("gitrepository.yaml parses as YAML");
6041 assert_eq!(
6042 kube_root_str_field(&parsed, KUBE_KEY_KIND),
6043 Some(FLUX_KIND_GIT_REPOSITORY),
6044 "gitrepository.yaml top-level kind must spell the lifted \
6045 FLUX_KIND_GIT_REPOSITORY ({FLUX_KIND_GIT_REPOSITORY:?}); a drifted \
6046 literal here routes the GitRepository outside the Flux v2 \
6047 source-controller's CRD registration",
6048 );
6049 }
6050
6051 #[test]
6052 fn cluster_bundle_helmrelease_source_ref_kind_uses_lifted_flux_kind_git_repository() {
6053 // Sibling-axis pin to
6054 // `cluster_bundle_gitrepository_kind_uses_lifted_flux_kind_git_repository`:
6055 // the rendered `helmrelease.yaml`'s `spec.chart.spec.sourceRef.kind`
6056 // axis is the Flux v2 contract pairing the HelmRelease's chart-
6057 // source resolution to the sibling GitRepository's CRD
6058 // discriminator. Both axes must resolve to the same lifted
6059 // constant by value — a future Flux v3 rebrand on either axis
6060 // without a coordinated edit on the other would have silently
6061 // dangled the HelmRelease's chart sourceRef (apply-side: the
6062 // `helm-controller` never resolves a chart for the HelmRelease,
6063 // the rendered Servico chart never reconciles), with the failure
6064 // surfacing far from the rebrand commit's source at
6065 // `kubectl describe helmrelease` time. This is the one of the
6066 // three call sites whose drift the apiserver can't self-locate
6067 // (top-level kind typos surface as "no kind 'X' is registered"
6068 // at apply parse time; a nested sourceRef.kind typo silently
6069 // dangles a controller-side reference).
6070 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6071 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6072 let hr = files
6073 .iter()
6074 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6075 .expect("helmrelease.yaml present");
6076 let parsed: serde_yaml::Value =
6077 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
6078 let source_ref_kind = parsed
6079 .get(KUBE_KEY_SPEC)
6080 .and_then(|s| s.get(FLUX_KEY_CHART))
6081 .and_then(|c| c.get(KUBE_KEY_SPEC))
6082 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
6083 .and_then(|r| r.get(KUBE_KEY_KIND))
6084 .and_then(|k| k.as_str())
6085 .expect("helmrelease.yaml spec.chart.spec.sourceRef.kind present");
6086 assert_eq!(
6087 source_ref_kind, FLUX_KIND_GIT_REPOSITORY,
6088 "helmrelease.yaml spec.chart.spec.sourceRef.kind must spell the \
6089 lifted FLUX_KIND_GIT_REPOSITORY ({FLUX_KIND_GIT_REPOSITORY:?}); a \
6090 drifted literal here dangles the HelmRelease's chart sourceRef \
6091 at the Flux v2 source-controller's CRD registration",
6092 );
6093 }
6094
6095 #[test]
6096 fn cluster_bundle_kustomization_source_ref_kind_uses_lifted_flux_kind_git_repository() {
6097 // Sibling-axis pin to
6098 // `cluster_bundle_gitrepository_kind_uses_lifted_flux_kind_git_repository`
6099 // / `cluster_bundle_helmrelease_source_ref_kind_uses_lifted_flux_kind_git_repository`:
6100 // the rendered `kustomization.yaml`'s `spec.sourceRef.kind` axis is
6101 // the Flux v2 contract pairing the parent Kustomization's source
6102 // resolution to the cluster's bootstrap GitRepository's CRD
6103 // discriminator (paired with [`DEFAULT_FLUX_SYSTEM_NAMESPACE`] on
6104 // the namespace axis). Completes the three-axis pin set so any
6105 // local re-introduction of an inline `GitRepository` literal at
6106 // any one of the three rendered Flux bundle axes is a build-time
6107 // test failure, not a silent apply-time dangling-sourceRef
6108 // reconciliation freeze.
6109 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6110 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6111 let kz = files
6112 .iter()
6113 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6114 .expect("kustomization.yaml present");
6115 let parsed: serde_yaml::Value =
6116 serde_yaml::from_str(&kz.contents).expect("kustomization.yaml parses as YAML");
6117 let source_ref_kind = parsed
6118 .get(KUBE_KEY_SPEC)
6119 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
6120 .and_then(|r| r.get(KUBE_KEY_KIND))
6121 .and_then(|k| k.as_str())
6122 .expect("kustomization.yaml spec.sourceRef.kind present");
6123 assert_eq!(
6124 source_ref_kind, FLUX_KIND_GIT_REPOSITORY,
6125 "kustomization.yaml spec.sourceRef.kind must spell the lifted \
6126 FLUX_KIND_GIT_REPOSITORY ({FLUX_KIND_GIT_REPOSITORY:?}); a drifted \
6127 literal here dangles the parent Kustomization's sourceRef at \
6128 the Flux v2 source-controller's CRD registration",
6129 );
6130 }
6131
6132 #[test]
6133 fn cluster_bundle_three_git_repository_kind_axes_share_one_lifted_constant() {
6134 // Cross-axis triplet invariant: the three rendered Flux bundle
6135 // axes that name the Flux v2 `GitRepository` CRD discriminator
6136 // (gitrepository.yaml top-level kind, helmrelease.yaml
6137 // spec.chart.spec.sourceRef.kind, kustomization.yaml
6138 // spec.sourceRef.kind) all consult one lifted `&'static str`.
6139 // The apiserver-side CRD resolution contract is the
6140 // `(apiVersion, kind)` tuple keyed against the registered
6141 // `CustomResourceDefinition`; the three axes must move
6142 // together on any future Flux v3 CRD rename (e.g. `GitSource`)
6143 // for the rendered HelmRelease's chart sourceRef + the parent
6144 // Kustomization's sourceRef to bind to the sibling
6145 // GitRepository's renamed kind discriminator. Peer to the
6146 // sibling [`flux_controller_triplet_api_versions_share_toolkit_fluxcd_io_root`]
6147 // cross-axis pin on the apiVersion half of the same CRD-lookup
6148 // tuple.
6149 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6150 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6151
6152 let gr_kind = serde_yaml::from_str::<serde_yaml::Value>(
6153 &files
6154 .iter()
6155 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
6156 .unwrap()
6157 .contents,
6158 )
6159 .unwrap()
6160 .get(KUBE_KEY_KIND)
6161 .and_then(|v| v.as_str())
6162 .map(String::from)
6163 .unwrap();
6164
6165 let hr_source_kind = serde_yaml::from_str::<serde_yaml::Value>(
6166 &files
6167 .iter()
6168 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6169 .unwrap()
6170 .contents,
6171 )
6172 .unwrap()
6173 .get(KUBE_KEY_SPEC)
6174 .and_then(|s| s.get(FLUX_KEY_CHART))
6175 .and_then(|c| c.get(KUBE_KEY_SPEC))
6176 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
6177 .and_then(|r| r.get(KUBE_KEY_KIND))
6178 .and_then(|v| v.as_str())
6179 .map(String::from)
6180 .unwrap();
6181
6182 let kz_source_kind = serde_yaml::from_str::<serde_yaml::Value>(
6183 &files
6184 .iter()
6185 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6186 .unwrap()
6187 .contents,
6188 )
6189 .unwrap()
6190 .get(KUBE_KEY_SPEC)
6191 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
6192 .and_then(|r| r.get(KUBE_KEY_KIND))
6193 .and_then(|v| v.as_str())
6194 .map(String::from)
6195 .unwrap();
6196
6197 assert_eq!(gr_kind, FLUX_KIND_GIT_REPOSITORY);
6198 assert_eq!(hr_source_kind, FLUX_KIND_GIT_REPOSITORY);
6199 assert_eq!(kz_source_kind, FLUX_KIND_GIT_REPOSITORY);
6200 assert_eq!(
6201 gr_kind, hr_source_kind,
6202 "gitrepository.yaml top-level kind and helmrelease.yaml \
6203 spec.chart.spec.sourceRef.kind must spell the same lifted \
6204 constant — drift here dangles the HelmRelease's chart sourceRef"
6205 );
6206 assert_eq!(
6207 gr_kind, kz_source_kind,
6208 "gitrepository.yaml top-level kind and kustomization.yaml \
6209 spec.sourceRef.kind must spell the same lifted constant — \
6210 drift here dangles the parent Kustomization's sourceRef"
6211 );
6212 }
6213
6214 #[test]
6215 fn flux_kind_helm_release_re_export_points_at_caixa_core_canonical() {
6216 // The renderer's `pub use caixa_core::FLUX_KIND_HELM_RELEASE` is
6217 // the single source of truth for the Flux v2 `HelmRelease` CRD
6218 // `kind` discriminator the rendered Flux bundle's two
6219 // `HelmRelease`-naming axes declare (the `helmrelease.yaml`
6220 // top-level `kind`, the `kustomization.yaml`
6221 // `spec.healthChecks[].kind`). Pin the equality (and the
6222 // static-data identity, peer with the sibling
6223 // [`flux_kind_git_repository_re_export_points_at_caixa_core_canonical`]
6224 // pin) so any local re-introduction of a sibling `pub const
6225 // FLUX_KIND_HELM_RELEASE: &str = "…"` (the canonical drift
6226 // footgun this lift closes — two production-code consumers of
6227 // the load-bearing Flux v2 `HelmRelease` CRD `kind`
6228 // discriminator inside the cluster_bundle templates, lifted to
6229 // one re-export at the caixa-core boundary) is a build-time
6230 // test failure naming the offending drift, not a silent
6231 // apply-time `helm-controller` resolution dangle or a
6232 // perpetually-`Reconciling` parent Kustomization.
6233 caixa_core::assert_str_reexport_identity(
6234 "FLUX_KIND_HELM_RELEASE",
6235 FLUX_KIND_HELM_RELEASE,
6236 caixa_core::FLUX_KIND_HELM_RELEASE,
6237 );
6238 }
6239
6240 #[test]
6241 fn cluster_bundle_helmrelease_kind_uses_lifted_flux_kind_helm_release() {
6242 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`
6243 // top-level `kind` axis — the load-bearing K8s CRD discriminator
6244 // the Flux v2 `helm-controller` resolves the rendered document
6245 // against — must resolve to the lifted
6246 // [`FLUX_KIND_HELM_RELEASE`] verbatim. Before this lift the
6247 // helmrelease template carried an inline `HelmRelease` literal
6248 // at one of two sibling production-code call sites across the
6249 // cluster_bundle templates; the apiserver-side CRD resolution
6250 // contract is the `(apiVersion, kind)` tuple keyed against the
6251 // registered `CustomResourceDefinition`, so drift on the kind
6252 // axis is exactly as load-bearing as drift on the sibling
6253 // [`FLUX_HELMRELEASE_API_VERSION`] axis (a future Flux v3
6254 // rebrand on this axis without a coordinated edit on the
6255 // sibling healthChecks[].kind axis silently lands the rendered
6256 // `HelmRelease` outside the helm-controller's `Watches`).
6257 // Peer with [`cluster_bundle_helmrelease_uses_lifted_flux_api_version`]
6258 // on the sibling apiVersion half of the same CRD-lookup tuple,
6259 // and with
6260 // [`cluster_bundle_gitrepository_kind_uses_lifted_flux_kind_git_repository`]
6261 // on the sibling Flux-v2 source-controller CRD kind axis.
6262 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6263 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6264 let hr = files
6265 .iter()
6266 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6267 .expect("helmrelease.yaml present");
6268 let parsed: serde_yaml::Value =
6269 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
6270 assert_eq!(
6271 kube_root_str_field(&parsed, KUBE_KEY_KIND),
6272 Some(FLUX_KIND_HELM_RELEASE),
6273 "helmrelease.yaml top-level kind must spell the lifted \
6274 FLUX_KIND_HELM_RELEASE ({FLUX_KIND_HELM_RELEASE:?}); a drifted \
6275 literal here routes the HelmRelease outside the Flux v2 \
6276 helm-controller's CRD registration",
6277 );
6278 }
6279
6280 #[test]
6281 fn cluster_bundle_kustomization_health_check_kind_uses_lifted_flux_kind_helm_release() {
6282 // Sibling-axis pin to
6283 // `cluster_bundle_helmrelease_kind_uses_lifted_flux_kind_helm_release`:
6284 // the rendered `kustomization.yaml`'s
6285 // `spec.healthChecks[].kind` axis is the Flux v2 contract
6286 // pairing the parent Kustomization's per-resource health gate
6287 // to the sibling HelmRelease's CRD discriminator. Both axes
6288 // must resolve to the same lifted constant by value — a
6289 // future Flux v3 rebrand on either axis without a coordinated
6290 // edit on the other would have silently pinned the parent
6291 // Kustomization at `Reconciling` forever (apply-side: the
6292 // `kustomize-controller` perpetually re-evaluates an
6293 // unmatched health gate, the Kustomization never declares
6294 // its reconcile complete, every downstream `dependsOn` chain
6295 // freezes), with the failure surfacing far from the rebrand
6296 // commit's source at `kubectl describe kustomization` time.
6297 // This is one of the two call sites whose drift the
6298 // apiserver can't self-locate (top-level kind typos surface
6299 // as "no kind 'X' is registered" at apply parse time; a
6300 // healthChecks[].kind typo silently dangles a controller-side
6301 // health gate). Completes the two-axis pin set so any local
6302 // re-introduction of an inline `HelmRelease` literal at
6303 // either of the two rendered Flux bundle axes is a
6304 // build-time test failure, not a silent apply-time stuck-
6305 // Reconciling reconciliation freeze.
6306 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6307 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6308 let kz = files
6309 .iter()
6310 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6311 .expect("kustomization.yaml present");
6312 let parsed: serde_yaml::Value =
6313 serde_yaml::from_str(&kz.contents).expect("kustomization.yaml parses as YAML");
6314 let health_checks = parsed
6315 .get(KUBE_KEY_SPEC)
6316 .and_then(|s| s.get(FLUX_KEY_HEALTH_CHECKS))
6317 .and_then(|h| h.as_sequence())
6318 .expect("kustomization.yaml spec.healthChecks present");
6319 assert!(
6320 !health_checks.is_empty(),
6321 "kustomization.yaml spec.healthChecks must carry at least one \
6322 entry — the HelmRelease health gate is the canonical pleme-io \
6323 Flux bundle invariant"
6324 );
6325 let health_kind = health_checks[0]
6326 .get(KUBE_KEY_KIND)
6327 .and_then(|k| k.as_str())
6328 .expect("kustomization.yaml spec.healthChecks[0].kind present");
6329 assert_eq!(
6330 health_kind, FLUX_KIND_HELM_RELEASE,
6331 "kustomization.yaml spec.healthChecks[0].kind must spell the \
6332 lifted FLUX_KIND_HELM_RELEASE ({FLUX_KIND_HELM_RELEASE:?}); a \
6333 drifted literal here dangles the parent Kustomization at \
6334 `Reconciling` forever at the Flux v2 kustomize-controller's \
6335 health-gate evaluation",
6336 );
6337 }
6338
6339 #[test]
6340 fn cluster_bundle_two_helm_release_kind_axes_share_one_lifted_constant() {
6341 // Cross-axis pair invariant: the two rendered Flux bundle axes
6342 // that name the Flux v2 `HelmRelease` CRD discriminator
6343 // (helmrelease.yaml top-level kind, kustomization.yaml
6344 // spec.healthChecks[].kind) both consult one lifted
6345 // `&'static str`. The apiserver-side CRD resolution contract
6346 // is the `(apiVersion, kind)` tuple keyed against the
6347 // registered `CustomResourceDefinition`; the two axes must
6348 // move together on any future Flux v3 CRD rename (e.g.
6349 // `ChartRelease`) for the parent Kustomization's health gate
6350 // to bind to the sibling HelmRelease's renamed kind
6351 // discriminator. Peer to the sibling
6352 // [`cluster_bundle_three_git_repository_kind_axes_share_one_lifted_constant`]
6353 // cross-axis pin on the Flux v2 source-controller CRD kind
6354 // axis.
6355 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6356 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6357
6358 let hr_kind = serde_yaml::from_str::<serde_yaml::Value>(
6359 &files
6360 .iter()
6361 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6362 .unwrap()
6363 .contents,
6364 )
6365 .unwrap()
6366 .get(KUBE_KEY_KIND)
6367 .and_then(|v| v.as_str())
6368 .map(String::from)
6369 .unwrap();
6370
6371 let kz_health_kind = serde_yaml::from_str::<serde_yaml::Value>(
6372 &files
6373 .iter()
6374 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6375 .unwrap()
6376 .contents,
6377 )
6378 .unwrap()
6379 .get(KUBE_KEY_SPEC)
6380 .and_then(|s| s.get(FLUX_KEY_HEALTH_CHECKS))
6381 .and_then(|h| h.as_sequence())
6382 .and_then(|seq| seq.first())
6383 .and_then(|e| e.get(KUBE_KEY_KIND))
6384 .and_then(|v| v.as_str())
6385 .map(String::from)
6386 .unwrap();
6387
6388 assert_eq!(hr_kind, FLUX_KIND_HELM_RELEASE);
6389 assert_eq!(kz_health_kind, FLUX_KIND_HELM_RELEASE);
6390 assert_eq!(
6391 hr_kind, kz_health_kind,
6392 "helmrelease.yaml top-level kind and kustomization.yaml \
6393 spec.healthChecks[].kind must spell the same lifted constant \
6394 — drift here dangles the parent Kustomization's health gate \
6395 at the Flux v2 kustomize-controller"
6396 );
6397 }
6398
6399 #[test]
6400 fn flux_kind_kustomization_re_export_points_at_caixa_core_canonical() {
6401 // The renderer's `pub use caixa_core::FLUX_KIND_KUSTOMIZATION` is
6402 // the single source of truth for the Flux v2 `Kustomization` CRD
6403 // `kind` discriminator the rendered Flux bundle's
6404 // `Kustomization`-naming axis declares (the `kustomization.yaml`
6405 // top-level `kind`). Pin the equality (and the static-data
6406 // identity, peer with the sibling
6407 // [`flux_kind_git_repository_re_export_points_at_caixa_core_canonical`]
6408 // /
6409 // [`flux_kind_helm_release_re_export_points_at_caixa_core_canonical`]
6410 // pins) so any local re-introduction of a sibling
6411 // `pub const FLUX_KIND_KUSTOMIZATION: &str = "…"` (the canonical
6412 // drift footgun this lift closes — the load-bearing Flux v2
6413 // `Kustomization` CRD `kind` discriminator inside the
6414 // cluster_bundle template, lifted to one re-export at the
6415 // caixa-core boundary) is a build-time test failure naming the
6416 // offending drift, not a silent apply-time
6417 // `kustomize-controller` CRD-lookup miss that perpetually
6418 // freezes the rendered parent Kustomization and every
6419 // downstream per-Servico `dependsOn` chain.
6420 caixa_core::assert_str_reexport_identity(
6421 "FLUX_KIND_KUSTOMIZATION",
6422 FLUX_KIND_KUSTOMIZATION,
6423 caixa_core::FLUX_KIND_KUSTOMIZATION,
6424 );
6425 }
6426
6427 #[test]
6428 fn flux_key_source_ref_re_export_points_at_caixa_core_canonical() {
6429 // The renderer's `pub use caixa_core::FLUX_KEY_SOURCE_REF` is the
6430 // single source of truth for the Flux v2 per-`HelmRelease` /
6431 // `Kustomization` source-reference container-axis key the
6432 // rendered bundle documents mount their per-CR `(kind, name,
6433 // namespace)` reference triple under. Pin the equality (and the
6434 // static-data identity, peer with the sibling
6435 // [`flux_kind_git_repository_re_export_points_at_caixa_core_canonical`]
6436 // / [`flux_kind_helm_release_re_export_points_at_caixa_core_canonical`]
6437 // / [`flux_kind_kustomization_re_export_points_at_caixa_core_canonical`]
6438 // pins on the sibling per-CRD kind-discriminator surface) so any
6439 // local re-introduction of a sibling `pub const
6440 // FLUX_KEY_SOURCE_REF: &str = "…"` (the canonical drift footgun
6441 // where a sibling local `pub const` could happen to carry the
6442 // same string at the source while pointing at a different
6443 // `&'static` allocation) is a build-time test failure naming
6444 // the offending drift, not a silent apply-time dangling-
6445 // sourceRef reconciliation freeze (a rebrand on this axis
6446 // without a coordinated caixa-core edit silently dangles both
6447 // the `HelmRelease.spec.chart.spec.sourceRef` chart resolution
6448 // + the parent `Kustomization.spec.sourceRef` source resolution
6449 // at the Flux v2 source-controller's CRD registration; the
6450 // dependent per-Servico `dependsOn` chain freezes at apply time
6451 // with no field naming the container-axis-drift root cause).
6452 // Closes the sibling re-export identity axis on the same
6453 // trajectory the peer per-CRD-`kind`-discriminator pins carry.
6454 caixa_core::assert_str_reexport_identity(
6455 "FLUX_KEY_SOURCE_REF",
6456 FLUX_KEY_SOURCE_REF,
6457 caixa_core::FLUX_KEY_SOURCE_REF,
6458 );
6459 }
6460
6461 #[test]
6462 fn cluster_bundle_helmrelease_spec_chart_spec_source_ref_key_pins_lifted_flux_key_source_ref() {
6463 // Production-emit pin traversing a rendered `helmrelease.yaml`
6464 // document via parsed YAML: the `spec.chart.spec.sourceRef:\n`
6465 // sub-block header key baked into the [`cluster_bundle`]
6466 // `helmrelease.yaml` format-string template — the container-axis
6467 // key nesting the Flux v2 `HelmChartTemplate`'s per-CR
6468 // source-of-truth `(kind, name, namespace)` reference triple —
6469 // must resolve at the lifted [`FLUX_KEY_SOURCE_REF`] verbatim
6470 // byte-value. Before this sweep the site inlined `sourceRef:\n`
6471 // as a literal beside its sibling lifted `{chart_key}:` /
6472 // `{values_key}:` axes; a caixa-core rebrand of the const would
6473 // silently drift the probe path (`.get(FLUX_KEY_SOURCE_REF)`)
6474 // away from the emit path (baked `sourceRef:\n`), and a future
6475 // Flux v3 rename would land in the const while the emit-side
6476 // format-string template silently kept the old byte sequence.
6477 // The sweep threads the const through a `{source_ref_key}`
6478 // named-arg interpolation so both paths consult one
6479 // `&'static str`; this pin traverses the rendered document at
6480 // the lifted-const-keyed navigation and asserts a populated
6481 // sub-mapping (the `(kind, name, namespace)` triple) resolves
6482 // there, verifying that the emit path spells the exact const
6483 // byte-value. A regression that re-introduces an inline literal
6484 // in the format-string template surfaces as a `None` at the
6485 // lifted-const-keyed lookup. Peer to the sibling
6486 // [`cluster_bundle_kustomization_spec_source_ref_key_pins_lifted_flux_key_source_ref`]
6487 // pin closing the second production emit site on the same
6488 // container-axis, and to the sibling
6489 // [`cluster_bundle_helmrelease_values_block_uses_lifted_flux_key_values`]
6490 // pin on the sibling per-`HelmRelease` body-key surface.
6491 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6492 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6493 let hr = files
6494 .iter()
6495 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6496 .expect("helmrelease.yaml present");
6497 let parsed: serde_yaml::Value =
6498 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
6499 let source_ref = parsed
6500 .get(KUBE_KEY_SPEC)
6501 .and_then(|s| s.get(FLUX_KEY_CHART))
6502 .and_then(|c| c.get(KUBE_KEY_SPEC))
6503 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
6504 .and_then(|r| r.as_mapping())
6505 .expect("spec.chart.spec.<FLUX_KEY_SOURCE_REF> mapping present");
6506 assert!(
6507 !source_ref.is_empty(),
6508 "spec.chart.spec.<FLUX_KEY_SOURCE_REF> ({FLUX_KEY_SOURCE_REF:?}) \
6509 must carry the `(kind, name, namespace)` reference triple; drift \
6510 on this container-axis key silently dangles the HelmRelease's \
6511 chart resolution at the Flux v2 source-controller's CRD \
6512 registration"
6513 );
6514 }
6515
6516 #[test]
6517 fn cluster_bundle_kustomization_spec_source_ref_key_pins_lifted_flux_key_source_ref() {
6518 // Production-emit pin traversing a rendered `kustomization.yaml`
6519 // document via parsed YAML: the `spec.sourceRef:\n` sub-block
6520 // header key baked into the [`cluster_bundle`]
6521 // `kustomization.yaml` format-string template — the
6522 // container-axis key nesting the parent `Kustomization`'s
6523 // source-of-truth `(kind, name)` reference pair pointing back at
6524 // the cluster's bootstrap `GitRepository` — must resolve at the
6525 // lifted [`FLUX_KEY_SOURCE_REF`] verbatim byte-value. Before
6526 // this sweep the site inlined `sourceRef:\n` as a literal
6527 // beside its sibling lifted `{interval_key}:` /
6528 // `{health_checks_key}:` axes; a caixa-core rebrand of the
6529 // const would silently drift the probe path away from the emit
6530 // path, and a future Flux v3 rename would land in the const
6531 // while this format-string template silently kept the old byte
6532 // sequence. The sweep threads the const through a
6533 // `{source_ref_key}` named-arg interpolation so both paths
6534 // consult one `&'static str`; this pin traverses the rendered
6535 // document at the lifted-const-keyed navigation and asserts a
6536 // populated sub-mapping resolves there. A regression that
6537 // re-introduces an inline literal surfaces as a `None` at the
6538 // lifted-const-keyed lookup. Peer to the sibling
6539 // [`cluster_bundle_helmrelease_spec_chart_spec_source_ref_key_pins_lifted_flux_key_source_ref`]
6540 // pin closing the first production emit site on the same
6541 // container-axis, together closing the two-site production
6542 // emit sweep the peer [`FLUX_KEY_SOURCE_REF`] doc block calls
6543 // out.
6544 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6545 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6546 let kz = files
6547 .iter()
6548 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6549 .expect("kustomization.yaml present");
6550 let parsed: serde_yaml::Value =
6551 serde_yaml::from_str(&kz.contents).expect("kustomization.yaml parses as YAML");
6552 let source_ref = parsed
6553 .get(KUBE_KEY_SPEC)
6554 .and_then(|s| s.get(FLUX_KEY_SOURCE_REF))
6555 .and_then(|r| r.as_mapping())
6556 .expect("spec.<FLUX_KEY_SOURCE_REF> mapping present");
6557 assert!(
6558 !source_ref.is_empty(),
6559 "spec.<FLUX_KEY_SOURCE_REF> ({FLUX_KEY_SOURCE_REF:?}) must \
6560 carry the `(kind, name)` reference pair pointing at the \
6561 cluster's bootstrap GitRepository; drift on this \
6562 container-axis key silently dangles the parent \
6563 Kustomization's source resolution at the Flux v2 \
6564 source-controller's CRD registration"
6565 );
6566 }
6567
6568 #[test]
6569 fn flux_key_values_re_export_points_at_caixa_core_canonical() {
6570 // The renderer's `pub use caixa_core::FLUX_KEY_VALUES` is the
6571 // single source of truth for the Flux v2 per-`HelmRelease`
6572 // values-override block-body-axis key the rendered
6573 // `helmrelease.yaml` nests its per-cluster override YAML under.
6574 // Pin the equality (and the static-data identity, peer with the
6575 // sibling
6576 // [`flux_key_source_ref_re_export_points_at_caixa_core_canonical`]
6577 // pin on the sibling Flux v2 per-CR container-axis-key surface)
6578 // so any local re-introduction of a sibling `pub const
6579 // FLUX_KEY_VALUES: &str = "…"` (the canonical drift footgun
6580 // where a sibling local `pub const` could happen to carry the
6581 // same string at the source while pointing at a different
6582 // `&'static` allocation) is a build-time test failure naming
6583 // the offending drift, not a silent apply-time per-cluster-
6584 // override-routed-nowhere reconciliation (a rebrand on this
6585 // axis without a coordinated caixa-core edit silently routes
6586 // the per-cluster override YAML nowhere at Helm-render time;
6587 // the workload silently comes up with the referenced chart's
6588 // admission-time defaults, far from the source `caixa.lisp` /
6589 // the renderer's format-string template). Closes the sibling
6590 // re-export identity axis on the same trajectory the peer
6591 // [`flux_key_source_ref_re_export_points_at_caixa_core_canonical`]
6592 // pin carries.
6593 caixa_core::assert_str_reexport_identity(
6594 "FLUX_KEY_VALUES",
6595 FLUX_KEY_VALUES,
6596 caixa_core::FLUX_KEY_VALUES,
6597 );
6598 }
6599
6600 #[test]
6601 fn cluster_bundle_helmrelease_values_block_uses_lifted_flux_key_values() {
6602 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`'s
6603 // top-level `spec.values` block-body-axis key — the scope under
6604 // which per-cluster overrides reach the referenced chart at
6605 // Flux v2 `helm-controller` reconcile time — must resolve to the
6606 // lifted [`FLUX_KEY_VALUES`] verbatim. Before the lift this
6607 // site carried an inline `values:\n` literal in the format
6608 // string; a future Flux v3 rebrand on this axis (a hypothetical
6609 // upstream fluxcd/flux2 rename from `values` to `Values` /
6610 // `chartValues` / `overrides`, coordinated with the upstream
6611 // project's per-version deprecation cycle) without a
6612 // coordinated edit here would have silently routed the per-
6613 // cluster override YAML nowhere at `helm-controller` reconcile
6614 // time — the workload's per-cluster overrides never reach the
6615 // referenced chart, and the apply comes up with the chart's
6616 // admission-time defaults far from the rebrand commit's source.
6617 //
6618 // The pin is structural: parse the rendered YAML and assert the
6619 // per-`HelmRelease` values-override block-body-axis key resolves
6620 // under the lifted constant (not `.get("values")` — that is the
6621 // sibling literal-shape probe the peer test at line 1955 pins;
6622 // this test asserts the lifted-const-keyed navigation carries a
6623 // populated mapping under it). A regression that re-introduces
6624 // an inline literal in the format-string template surfaces as a
6625 // `None` at the lifted-const-keyed lookup (the inline literal
6626 // would survive, but the lifted-const-keyed assertion would
6627 // fail). Peer to the sibling
6628 // [`cluster_bundle_helmrelease_values_wrap_key_uses_lifted_constant`]
6629 // pin on the sibling per-`HelmRelease` inner-wrap-key surface
6630 // — extends the canonical-Flux-v2-per-`HelmRelease`-values-
6631 // navigation lift from the wrap-key axis onto the outer block-
6632 // body-axis this test targets.
6633 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6634 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6635 let hr = files
6636 .iter()
6637 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6638 .expect("helmrelease.yaml present");
6639 let parsed: serde_yaml::Value =
6640 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
6641 let values = parsed
6642 .get(KUBE_KEY_SPEC)
6643 .and_then(|s| s.get(FLUX_KEY_VALUES))
6644 .and_then(|v| v.as_mapping())
6645 .expect("spec.<FLUX_KEY_VALUES> mapping present");
6646 assert!(
6647 !values.is_empty(),
6648 "spec.<FLUX_KEY_VALUES> ({FLUX_KEY_VALUES:?}) must carry \
6649 at least the lifted-[`DEFAULT_LIBRARY_NAME`]-wrapped per-\
6650 cluster override block; drift on this block-body-axis key \
6651 silently routes overrides nowhere at helm-controller \
6652 reconcile time"
6653 );
6654 }
6655
6656 #[test]
6657 fn cluster_bundle_kustomization_kind_uses_lifted_flux_kind_kustomization() {
6658 // Fail-before-pass-after pin: the rendered `kustomization.yaml`
6659 // top-level `kind` axis — the load-bearing K8s CRD discriminator
6660 // the Flux v2 `kustomize-controller` resolves the rendered
6661 // document against — must resolve to the lifted
6662 // [`FLUX_KIND_KUSTOMIZATION`] verbatim. Before this lift the
6663 // kustomization template carried an inline `Kustomization`
6664 // literal; the apiserver-side CRD resolution contract is the
6665 // `(apiVersion, kind)` tuple keyed against the registered
6666 // `CustomResourceDefinition`, so drift on the kind axis is
6667 // exactly as load-bearing as drift on the sibling
6668 // [`FLUX_KUSTOMIZATION_API_VERSION`] axis (a future Flux v3
6669 // rebrand on this axis without a coordinated edit on the
6670 // sibling apiVersion axis silently lands the rendered
6671 // `Kustomization` outside the kustomize-controller's `Watches`
6672 // and surfaces at apply parse time as a non-self-locating
6673 // "no kind 'Kustomization' is registered" error far from the
6674 // rebrand commit's source). Peer with
6675 // [`cluster_bundle_kustomization_uses_lifted_flux_kustomization_api_version`]
6676 // on the sibling apiVersion half of the same CRD-lookup tuple,
6677 // and with
6678 // [`cluster_bundle_helmrelease_kind_uses_lifted_flux_kind_helm_release`]
6679 // /
6680 // [`cluster_bundle_gitrepository_kind_uses_lifted_flux_kind_git_repository`]
6681 // on the sibling Flux v2 controller-triplet CRD kind axes.
6682 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6683 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6684 let kz = files
6685 .iter()
6686 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6687 .expect("kustomization.yaml present");
6688 let parsed: serde_yaml::Value =
6689 serde_yaml::from_str(&kz.contents).expect("kustomization.yaml parses as YAML");
6690 assert_eq!(
6691 kube_root_str_field(&parsed, KUBE_KEY_KIND),
6692 Some(FLUX_KIND_KUSTOMIZATION),
6693 "kustomization.yaml top-level kind must spell the lifted \
6694 FLUX_KIND_KUSTOMIZATION ({FLUX_KIND_KUSTOMIZATION:?}); a drifted \
6695 literal here routes the Kustomization outside the Flux v2 \
6696 kustomize-controller's CRD registration",
6697 );
6698 }
6699
6700 #[test]
6701 fn flux_key_chart_re_export_points_at_caixa_core_canonical() {
6702 // The renderer's `pub use caixa_core::FLUX_KEY_CHART` is the
6703 // single source of truth for the Flux v2 per-`HelmRelease`
6704 // chart-template container-axis key the rendered
6705 // `helmrelease.yaml` nests its per-CR `HelmChartTemplate`
6706 // sub-document under. Pin the equality (and the static-data
6707 // identity, peer with the sibling
6708 // [`flux_key_source_ref_re_export_points_at_caixa_core_canonical`]
6709 // / [`flux_key_values_re_export_points_at_caixa_core_canonical`]
6710 // pins on the sibling Flux v2 per-`HelmRelease` body-key
6711 // surfaces) so any local re-introduction of a sibling `pub
6712 // const FLUX_KEY_CHART: &str = "…"` (the canonical drift
6713 // footgun where a sibling local `pub const` could happen to
6714 // carry the same string at the source while pointing at a
6715 // different `&'static` allocation) is a build-time test
6716 // failure naming the offending drift, not a silent apply-
6717 // time dangling-chart-template reconciliation freeze (a
6718 // rebrand on this axis without a coordinated caixa-core edit
6719 // silently dangles the `HelmRelease.spec.chart` chart-
6720 // template resolution at the Flux v2 helm-controller's CRD
6721 // registration; the referenced chart never resolves and the
6722 // per-Servico workload freezes at apply time with no field
6723 // naming the container-axis-drift root cause). Closes the
6724 // sibling re-export identity axis on the same trajectory the
6725 // peer per-CR body-key pins carry.
6726 caixa_core::assert_str_reexport_identity(
6727 "FLUX_KEY_CHART",
6728 FLUX_KEY_CHART,
6729 caixa_core::FLUX_KEY_CHART,
6730 );
6731 }
6732
6733 #[test]
6734 fn cluster_bundle_helmrelease_chart_block_uses_lifted_flux_key_chart() {
6735 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`'s
6736 // top-level `spec.chart` container-axis key — the scope under
6737 // which the Flux v2 `HelmChartTemplate` sub-document lives (the
6738 // `HelmChartTemplate.spec` block that carries the chart-name
6739 // leaf, source-of-truth reference triple, and per-CR reconcile
6740 // cadence the Flux v2 `helm-controller`'s per-CR reconcile loop
6741 // reads to source the referenced chart at Helm-render time) —
6742 // must resolve to the lifted [`FLUX_KEY_CHART`] verbatim.
6743 // Before the lift this site carried an inline `chart:\n`
6744 // literal in the format string; a future Flux v3 rebrand on
6745 // this axis (a hypothetical upstream fluxcd/flux2 rename from
6746 // `chart` to `Chart` / `chartTemplate` / `helmChart` /
6747 // `chartRef`, coordinated with the upstream project's per-
6748 // version deprecation cycle) without a coordinated edit here
6749 // would have silently dangled the whole chart-template block
6750 // at `helm-controller` reconcile time — the workload's
6751 // referenced chart never resolves, and the apply freezes at
6752 // the CRD-registration boundary far from the rebrand commit's
6753 // source.
6754 //
6755 // The pin is structural: parse the rendered YAML and assert
6756 // the per-`HelmRelease` chart-template container-axis key
6757 // resolves under the lifted constant with a populated
6758 // `HelmChartTemplate.spec` sub-mapping under it. A regression
6759 // that re-introduces an inline literal in the format-string
6760 // template surfaces as a `None` at the lifted-const-keyed
6761 // lookup. Peer to the sibling
6762 // [`cluster_bundle_helmrelease_values_block_uses_lifted_flux_key_values`]
6763 // pin on the sibling per-`HelmRelease` values-override block-
6764 // body-axis surface — extends the canonical-Flux-v2-per-
6765 // `HelmRelease`-body-key lifted-const-keyed pin discipline
6766 // from the values-override block-body-axis onto the sibling
6767 // chart-template container-axis this test targets.
6768 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6769 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6770 let hr = files
6771 .iter()
6772 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6773 .expect("helmrelease.yaml present");
6774 let parsed: serde_yaml::Value =
6775 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
6776 let chart = parsed
6777 .get(KUBE_KEY_SPEC)
6778 .and_then(|s| s.get(FLUX_KEY_CHART))
6779 .and_then(|v| v.as_mapping())
6780 .expect("spec.<FLUX_KEY_CHART> mapping present");
6781 assert!(
6782 !chart.is_empty(),
6783 "spec.<FLUX_KEY_CHART> ({FLUX_KEY_CHART:?}) must carry \
6784 at least the nested `HelmChartTemplate.spec` sub-document; \
6785 drift on this container-axis key silently dangles the \
6786 whole chart-template block at helm-controller reconcile time"
6787 );
6788 }
6789
6790 #[test]
6791 fn flux_helmchart_template_key_chart_re_export_points_at_caixa_core_canonical() {
6792 // The renderer's `pub use caixa_core::FLUX_HELMCHART_TEMPLATE_KEY_CHART`
6793 // is the single source of truth for the Flux v2 per-`HelmChartTemplate`
6794 // chart-NAME reference leaf-scalar-axis key the rendered
6795 // `helmrelease.yaml`'s `spec.chart.spec.chart` leaf-scalar-
6796 // valued field carries the chart-artifact name at the
6797 // helm-controller's per-CR reconcile-time chart-lookup axis.
6798 // Pin the equality (and the static-data identity, peer with
6799 // the sibling [`flux_key_chart_re_export_points_at_caixa_core_canonical`]
6800 // pin on the parent container-axis re-export the leaf-scalar-
6801 // axis nests inside) so any local re-introduction of a sibling
6802 // `pub const FLUX_HELMCHART_TEMPLATE_KEY_CHART: &str = "…"`
6803 // (the canonical drift footgun this lift closes — the one
6804 // production-code call site the `cluster_bundle`
6805 // `helmrelease.yaml` format-string template threaded the
6806 // chart-NAME leaf-scalar-key through, lifted to one re-export
6807 // at the caixa-core boundary) is a build-time test failure
6808 // naming the offending drift, not a silent apply-time
6809 // "chart 'unknown' not found in <source>" reconciliation
6810 // dangle the CRD's OpenAPI extra-property schema permits at
6811 // the apiserver.
6812 caixa_core::assert_str_reexport_identity(
6813 "FLUX_HELMCHART_TEMPLATE_KEY_CHART",
6814 FLUX_HELMCHART_TEMPLATE_KEY_CHART,
6815 caixa_core::FLUX_HELMCHART_TEMPLATE_KEY_CHART,
6816 );
6817 }
6818
6819 #[test]
6820 fn cluster_bundle_helmrelease_chart_name_leaf_uses_lifted_flux_helmchart_template_key_chart() {
6821 // Fail-before-pass-after pin: the rendered `helmrelease.yaml`'s
6822 // per-`HelmChartTemplate.spec.chart` chart-NAME reference
6823 // leaf-scalar-valued field — the load-bearing chart-lookup
6824 // scalar the Flux v2 helm-controller resolves the referenced
6825 // chart artifact through the sibling `sourceRef` triple's
6826 // source at reconcile time by — must resolve under the lifted
6827 // [`FLUX_HELMCHART_TEMPLATE_KEY_CHART`] leaf-scalar-axis key
6828 // and carry the `ClusterBundleOpts.chart_path` value verbatim.
6829 // Before this lift the leaf site carried an inline `chart:`
6830 // literal at the `cluster_bundle` `helmrelease.yaml` format-
6831 // string template's chart-name-leaf interpolation site — a
6832 // future Flux v3 rebrand on this axis (a hypothetical upstream
6833 // fluxcd/flux2 rename from `chart` to `Chart` / `chartRef` /
6834 // `chartName`) without a coordinated edit on the canonical
6835 // caixa-core const would have silently dangled the chart-
6836 // artifact resolution at the helm-controller's per-CR
6837 // reconcile-time chart-lookup with a non-self-locating
6838 // "chart 'unknown' not found in <source>" error far from the
6839 // rebrand commit's source. Peer to
6840 // [`cluster_bundle_helmrelease_chart_block_uses_lifted_flux_key_chart`]
6841 // on the parent container-axis surface — extends the pin
6842 // discipline one level beneath by asserting the chart-NAME
6843 // leaf-scalar under the container-axis carries the lifted
6844 // constant.
6845 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6846 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6847 let hr = files
6848 .iter()
6849 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
6850 .expect("helmrelease.yaml present");
6851 let parsed: serde_yaml::Value =
6852 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
6853 let chart_name = parsed
6854 .get(KUBE_KEY_SPEC)
6855 .and_then(|s| s.get(FLUX_KEY_CHART))
6856 .and_then(|c| c.get(KUBE_KEY_SPEC))
6857 .and_then(|s| s.get(FLUX_HELMCHART_TEMPLATE_KEY_CHART))
6858 .and_then(|n| n.as_str())
6859 .expect("spec.chart.spec.<FLUX_HELMCHART_TEMPLATE_KEY_CHART> scalar present");
6860 assert_eq!(
6861 chart_name,
6862 opts.chart_path,
6863 "spec.chart.spec.<FLUX_HELMCHART_TEMPLATE_KEY_CHART> \
6864 ({FLUX_HELMCHART_TEMPLATE_KEY_CHART:?}) leaf-scalar must carry the \
6865 ClusterBundleOpts.chart_path verbatim ({expected:?}); a drifted \
6866 key here silently dangles the chart-artifact resolution at the \
6867 Flux v2 helm-controller's per-CR reconcile-time chart-lookup axis",
6868 expected = opts.chart_path,
6869 );
6870 }
6871
6872 #[test]
6873 fn flux_key_health_checks_re_export_points_at_caixa_core_canonical() {
6874 // The renderer's `pub use caixa_core::FLUX_KEY_HEALTH_CHECKS` is
6875 // the single source of truth for the Flux v2 per-`Kustomization`
6876 // health-gate reference-list container-axis key the rendered
6877 // `kustomization.yaml` nests its per-entry
6878 // `[]NamespacedObjectKindReference` list under. Pin the
6879 // equality (and the static-data identity, peer with the sibling
6880 // [`flux_key_source_ref_re_export_points_at_caixa_core_canonical`]
6881 // / [`flux_key_chart_re_export_points_at_caixa_core_canonical`]
6882 // / [`flux_key_values_re_export_points_at_caixa_core_canonical`]
6883 // pins on the sibling Flux v2 body-key surfaces) so any local
6884 // re-introduction of a sibling `pub const FLUX_KEY_HEALTH_CHECKS:
6885 // &str = "…"` (the canonical drift footgun where a sibling local
6886 // `pub const` could happen to carry the same string at the
6887 // source while pointing at a different `&'static` allocation) is
6888 // a build-time test failure naming the offending drift, not a
6889 // silent apply-time dangling-health-gate reconciliation freeze
6890 // (a rebrand on this axis without a coordinated caixa-core edit
6891 // silently dangles the `Kustomization.spec.healthChecks` health-
6892 // gate at the Flux v2 kustomize-controller's per-CR reconcile
6893 // loop; the parent Kustomization stays at `Reconciling` forever
6894 // and the dependent per-cluster fleet-programs upsert chain
6895 // never sees `Ready=True` at apply time with no field naming
6896 // the container-axis-drift root cause). Closes the sibling re-
6897 // export identity axis on the same trajectory the peer per-CR
6898 // body-key pins carry — completes the quartet.
6899 caixa_core::assert_str_reexport_identity(
6900 "FLUX_KEY_HEALTH_CHECKS",
6901 FLUX_KEY_HEALTH_CHECKS,
6902 caixa_core::FLUX_KEY_HEALTH_CHECKS,
6903 );
6904 }
6905
6906 #[test]
6907 fn cluster_bundle_kustomization_health_checks_block_uses_lifted_flux_key_health_checks() {
6908 // Fail-before-pass-after pin: the rendered `kustomization.yaml`'s
6909 // top-level `spec.healthChecks` container-axis key — the scope
6910 // under which the Flux v2 `[]NamespacedObjectKindReference` list
6911 // lives (the per-entry `(apiVersion, kind, name, namespace)`
6912 // triples the Flux v2 `kustomize-controller`'s per-CR reconcile
6913 // loop reads to gate the parent Kustomization's `Ready=True`
6914 // transition on the referenced sibling `HelmRelease` reaching its
6915 // `HelmReleaseReady=True` condition) — must resolve to the
6916 // lifted [`FLUX_KEY_HEALTH_CHECKS`] verbatim. Before the lift
6917 // this site carried an inline `healthChecks:\n` literal in the
6918 // `kustomization` format string; a future Flux v3 rebrand on
6919 // this axis (a hypothetical upstream fluxcd/flux2 rename from
6920 // `healthChecks` to `HealthChecks` / `healthchecks` /
6921 // `healthcheck` / `health_checks` / `probes`, coordinated with
6922 // the upstream project's per-version deprecation cycle) without
6923 // a coordinated edit here would have silently dangled the whole
6924 // health-gate reference-list at `kustomize-controller` reconcile
6925 // time — the parent Kustomization stays at `Reconciling`
6926 // forever, and the dependent per-cluster fleet-programs upsert
6927 // chain never sees `Ready=True` far from the rebrand commit's
6928 // source.
6929 //
6930 // The pin is structural: parse the rendered YAML and assert the
6931 // per-`Kustomization` health-gate reference-list container-axis
6932 // key resolves under the lifted constant with a non-empty
6933 // sequence under it. A regression that re-introduces an inline
6934 // literal in the format-string template surfaces as a `None` at
6935 // the lifted-const-keyed lookup. Peer to the sibling
6936 // [`cluster_bundle_helmrelease_chart_block_uses_lifted_flux_key_chart`]
6937 // / [`cluster_bundle_helmrelease_values_block_uses_lifted_flux_key_values`]
6938 // pins on the sibling per-`HelmRelease` body-key surfaces —
6939 // extends the canonical-Flux-v2-body-key lifted-const-keyed pin
6940 // discipline from the per-`HelmRelease` triplet onto the sibling
6941 // per-`Kustomization` `spec.healthChecks` reference-list
6942 // container-axis this test targets, completing the quartet.
6943 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
6944 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
6945 let kz = files
6946 .iter()
6947 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
6948 .expect("kustomization.yaml present");
6949 let parsed: serde_yaml::Value =
6950 serde_yaml::from_str(&kz.contents).expect("kustomization.yaml parses as YAML");
6951 let health_checks = parsed
6952 .get(KUBE_KEY_SPEC)
6953 .and_then(|s| s.get(FLUX_KEY_HEALTH_CHECKS))
6954 .and_then(|v| v.as_sequence())
6955 .expect("spec.<FLUX_KEY_HEALTH_CHECKS> sequence present");
6956 assert!(
6957 !health_checks.is_empty(),
6958 "spec.<FLUX_KEY_HEALTH_CHECKS> ({FLUX_KEY_HEALTH_CHECKS:?}) must \
6959 carry at least one `[]NamespacedObjectKindReference` entry; \
6960 drift on this container-axis key silently dangles the whole \
6961 health-gate at kustomize-controller reconcile time and freezes \
6962 the parent Kustomization at `Reconciling`"
6963 );
6964 }
6965
6966 #[test]
6967 fn flux_key_interval_re_export_points_at_caixa_core_canonical() {
6968 // The renderer's `pub use caixa_core::FLUX_KEY_INTERVAL` is the
6969 // single source of truth for the Flux v2 per-CR reconcile-poll
6970 // cadence scalar-axis key the three rendered Flux documents
6971 // (`gitrepository.yaml`, `helmrelease.yaml`, `kustomization.yaml`)
6972 // each carry as their `spec.interval` scalar. Pin the equality
6973 // (and the static-data identity, peer with the sibling
6974 // [`flux_key_source_ref_re_export_points_at_caixa_core_canonical`]
6975 // / [`flux_key_chart_re_export_points_at_caixa_core_canonical`]
6976 // / [`flux_key_values_re_export_points_at_caixa_core_canonical`]
6977 // / [`flux_key_health_checks_re_export_points_at_caixa_core_canonical`]
6978 // pins on the sibling Flux v2 per-CR body-key surfaces) so any
6979 // local re-introduction of a sibling `pub const FLUX_KEY_INTERVAL:
6980 // &str = "…"` (the canonical drift footgun where a sibling local
6981 // `pub const` could happen to carry the same string at the
6982 // source while pointing at a different `&'static` allocation) is
6983 // a build-time test failure naming the offending drift, not a
6984 // silent apply-time three-way reconcile freeze (a rebrand on
6985 // this axis without a coordinated caixa-core edit silently drops
6986 // the per-CR reconcile schedule from all three Flux v2
6987 // controllers' per-CR watch registrations simultaneously — the
6988 // referenced Git source never re-polls / the referenced chart
6989 // never re-templates / the parent Kustomization never re-applies
6990 // at upstream drift, freezing the whole cluster's per-`caixa`
6991 // per-cluster bundle at the last-applied snapshot with no field
6992 // naming the axis-drift root cause). Closes the re-export
6993 // identity axis on the same trajectory the peer per-CR body-key
6994 // pins carry — extends the discipline from the per-CR body-key
6995 // quartet onto the sibling cross-CR-shared reconcile-poll cadence
6996 // scalar-axis every Flux v2 controller reads.
6997 caixa_core::assert_str_reexport_identity(
6998 "FLUX_KEY_INTERVAL",
6999 FLUX_KEY_INTERVAL,
7000 caixa_core::FLUX_KEY_INTERVAL,
7001 );
7002 }
7003
7004 #[test]
7005 fn flux_gitrepository_ref_key_tag_re_export_points_at_caixa_core_canonical() {
7006 // The renderer's `pub use caixa_core::FLUX_GITREPOSITORY_REF_KEY_TAG`
7007 // is the single source of truth for the FluxCD source-controller
7008 // `GitRepository.spec.ref.tag` sub-selector scalar-axis key the
7009 // rendered `gitrepository.yaml` document declares on the tag-arm
7010 // of the [`GitRefSpec`] discriminated-union. Pin the equality +
7011 // `&'static` static-data identity so any local re-introduction
7012 // of a sibling `pub const FLUX_GITREPOSITORY_REF_KEY_TAG: &str
7013 // = "…"` at this crate is a build-time test failure naming the
7014 // offending drift, not a silent apply-time `GitRepository`
7015 // sub-selector reroute at cluster-side reconcile time. Peer to
7016 // [`flux_key_interval_re_export_points_at_caixa_core_canonical`]
7017 // on the sibling per-CR body-key surface — pivots the
7018 // canonical-lifted-const single-sourcing discipline onto the
7019 // per-`GitRepository`-`spec.ref`-sub-selector axis.
7020 caixa_core::assert_str_reexport_identity(
7021 "FLUX_GITREPOSITORY_REF_KEY_TAG",
7022 FLUX_GITREPOSITORY_REF_KEY_TAG,
7023 caixa_core::FLUX_GITREPOSITORY_REF_KEY_TAG,
7024 );
7025 }
7026
7027 #[test]
7028 fn flux_gitrepository_ref_key_branch_re_export_points_at_caixa_core_canonical() {
7029 // Peer of
7030 // [`flux_gitrepository_ref_key_tag_re_export_points_at_caixa_core_canonical`]
7031 // on the branch-arm of the FluxCD source-controller
7032 // `GitRepository.spec.ref` discriminated-union axis.
7033 caixa_core::assert_str_reexport_identity(
7034 "FLUX_GITREPOSITORY_REF_KEY_BRANCH",
7035 FLUX_GITREPOSITORY_REF_KEY_BRANCH,
7036 caixa_core::FLUX_GITREPOSITORY_REF_KEY_BRANCH,
7037 );
7038 }
7039
7040 #[test]
7041 fn flux_gitrepository_ref_key_commit_re_export_points_at_caixa_core_canonical() {
7042 // Peer of
7043 // [`flux_gitrepository_ref_key_tag_re_export_points_at_caixa_core_canonical`]
7044 // on the commit-arm of the FluxCD source-controller
7045 // `GitRepository.spec.ref` discriminated-union axis.
7046 caixa_core::assert_str_reexport_identity(
7047 "FLUX_GITREPOSITORY_REF_KEY_COMMIT",
7048 FLUX_GITREPOSITORY_REF_KEY_COMMIT,
7049 caixa_core::FLUX_GITREPOSITORY_REF_KEY_COMMIT,
7050 );
7051 }
7052
7053 #[test]
7054 fn flux_gitrepository_key_ref_re_export_points_at_caixa_core_canonical() {
7055 // Bridge-arm pin: the re-exported FLUX_GITREPOSITORY_KEY_REF
7056 // resolves to the canonical `"ref"` byte + `&'static`
7057 // allocation from caixa-core, closing the local-`pub const`-
7058 // shadow footgun where a sibling `pub const
7059 // FLUX_GITREPOSITORY_KEY_REF: &str = "…"` in this crate could
7060 // silently carry the same string at the source while pointing
7061 // at a different `&'static` allocation. Peer of the sibling
7062 // [`flux_gitrepository_ref_key_tag_re_export_points_at_caixa_core_canonical`]
7063 // / [`flux_gitrepository_ref_key_branch_re_export_points_at_caixa_core_canonical`]
7064 // / [`flux_gitrepository_ref_key_commit_re_export_points_at_caixa_core_canonical`]
7065 // pins on the sibling per-shape arm axes of the FluxCD source-
7066 // controller `GitRepository.spec.ref` discriminated-union — closes
7067 // the parent-container-axis KEY pin above the already-pinned
7068 // per-shape arm sub-selector-KEY triple, so the whole per-
7069 // `GitRepository` `spec.ref` sub-schema (parent container-axis
7070 // KEY + per-shape arm sub-selector-KEY triple) now navigates
7071 // through four caixa-core `&'static str`s pinned in coordination.
7072 caixa_core::assert_str_reexport_identity(
7073 "FLUX_GITREPOSITORY_KEY_REF",
7074 FLUX_GITREPOSITORY_KEY_REF,
7075 caixa_core::FLUX_GITREPOSITORY_KEY_REF,
7076 );
7077 }
7078
7079 #[test]
7080 fn cluster_bundle_gitrepository_spec_ref_key_pins_lifted_flux_gitrepository_key_ref() {
7081 // Production-emit pin: traverse a rendered `gitrepository.yaml`
7082 // document's `spec` block and assert the ref-selection
7083 // discriminated-union parent container-axis is keyed by the
7084 // *lifted* FLUX_GITREPOSITORY_KEY_REF (`"ref"`) verbatim — the
7085 // load-bearing per-`GitRepository` `spec.ref` container-axis
7086 // KEY the FluxCD source-controller reads to source the per-CR
7087 // git-clone refspec. Before the lift the writer template
7088 // carried an inline `ref:\n` literal at the sole
7089 // `format!("… spec:\n ref:\n{gitref_field}\n", …)` call in
7090 // `cluster_bundle`; a typo there (`"gitRef:"` / `"Ref:"` /
7091 // `"revision:"` / `"source:"`) would have silently landed a
7092 // `GitRepository` whose ref-selection container-axis the CRD
7093 // schema validator drops as unknown at admission, and every
7094 // downstream `HelmRelease` / `Kustomization` bundle document
7095 // that resolves through the sibling
7096 // `HelmRelease.spec.chart.spec.sourceRef` reference would have
7097 // silently dangled at the FluxCD apply chain with no field
7098 // naming the container-axis-drift root cause. Peer of the
7099 // sibling per-shape arm sub-selector-KEY test
7100 // [`cluster_bundle_gitrepository_ref_key_dispatches_per_variant_onto_lifted_consts`]
7101 // on the peer per-arm scalar-axis surface — closes the parent
7102 // container-axis pin above the already-pinned per-shape arm
7103 // sub-selector-KEY triple.
7104 let caixa = sample_caixa();
7105 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
7106 let files = cluster_bundle(&caixa, &opts).expect("bundle renders");
7107 let gr = files
7108 .iter()
7109 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
7110 .expect("gitrepository.yaml present");
7111 let parsed: serde_yaml::Value =
7112 serde_yaml::from_str(&gr.contents).expect("gitrepository.yaml parses as YAML");
7113 assert!(
7114 parsed
7115 .get(KUBE_KEY_SPEC)
7116 .and_then(|s| s.get(FLUX_GITREPOSITORY_KEY_REF))
7117 .is_some(),
7118 "rendered gitrepository.yaml must carry its ref-selection \
7119 container-axis at the lifted FLUX_GITREPOSITORY_KEY_REF key \
7120 verbatim (got: {:?})",
7121 gr.contents
7122 );
7123 }
7124
7125 #[test]
7126 fn flux_gitrepository_key_url_re_export_points_at_caixa_core_canonical() {
7127 // Bridge-arm pin: the re-exported FLUX_GITREPOSITORY_KEY_URL
7128 // resolves to the canonical `"url"` byte + `&'static`
7129 // allocation from caixa-core, closing the local-`pub const`-
7130 // shadow footgun where a sibling `pub const
7131 // FLUX_GITREPOSITORY_KEY_URL: &str = "…"` in this crate could
7132 // silently carry the same string at the source while pointing
7133 // at a different `&'static` allocation. Peer of the sibling
7134 // [`flux_gitrepository_key_ref_re_export_points_at_caixa_core_canonical`]
7135 // pin on the sibling per-CR `spec.ref` container-axis re-export
7136 // surface — closes the second per-`GitRepository` sub-block
7137 // key re-export identity pin, extending the discipline from
7138 // the container-axis surface onto the leaf-scalar remote-URL
7139 // axis.
7140 caixa_core::assert_str_reexport_identity(
7141 "FLUX_GITREPOSITORY_KEY_URL",
7142 FLUX_GITREPOSITORY_KEY_URL,
7143 caixa_core::FLUX_GITREPOSITORY_KEY_URL,
7144 );
7145 }
7146
7147 #[test]
7148 fn cluster_bundle_gitrepository_spec_url_key_pins_lifted_flux_gitrepository_key_url() {
7149 // Production-emit pin: traverse a rendered `gitrepository.yaml`
7150 // document's `spec` block and assert the remote-repo-URL leaf-
7151 // scalar-axis is keyed by the *lifted*
7152 // FLUX_GITREPOSITORY_KEY_URL (`"url"`) verbatim — the load-
7153 // bearing per-`GitRepository` `spec.url` leaf-scalar-axis KEY
7154 // the FluxCD source-controller reads to source the per-CR
7155 // git-remote clone target. Before the lift the writer template
7156 // carried an inline `url: {url}\n` literal at the sole
7157 // `format!(…)` call in `cluster_bundle`'s gitrepo composer;
7158 // a typo there (`"URL:"` / `"gitUrl:"` / `"repository:"` /
7159 // `"repo:"`) would have silently landed a `GitRepository`
7160 // whose CRD schema validator drops the URL field as unknown
7161 // at admission, the per-Servico artifact would never populate,
7162 // and every downstream `HelmRelease` / `Kustomization` bundle
7163 // document would silently no-op at reconcile time with an
7164 // empty artifact. Peer of the sibling per-container-axis KEY
7165 // test
7166 // [`cluster_bundle_gitrepository_spec_ref_key_pins_lifted_flux_gitrepository_key_ref`]
7167 // on the peer `spec.ref` container-axis surface — extends the
7168 // per-CR sub-block key pin discipline from the ref-selection
7169 // container-axis onto the remote-URL leaf-scalar-axis.
7170 let caixa = sample_caixa();
7171 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
7172 let files = cluster_bundle(&caixa, &opts).expect("bundle renders");
7173 let gr = files
7174 .iter()
7175 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
7176 .expect("gitrepository.yaml present");
7177 let parsed: serde_yaml::Value =
7178 serde_yaml::from_str(&gr.contents).expect("gitrepository.yaml parses as YAML");
7179 let url = parsed
7180 .get(KUBE_KEY_SPEC)
7181 .and_then(|s| s.get(FLUX_GITREPOSITORY_KEY_URL))
7182 .and_then(|u| u.as_str())
7183 .expect(
7184 "rendered gitrepository.yaml must carry its remote-URL leaf-scalar \
7185 axis at the lifted FLUX_GITREPOSITORY_KEY_URL key verbatim",
7186 );
7187 assert!(
7188 !url.is_empty(),
7189 "spec.url leaf-scalar must resolve to a non-empty git-remote clone \
7190 target — a drifted key would collapse the readback to None, an \
7191 empty string would break the source-controller's per-CR clone step"
7192 );
7193 }
7194
7195 #[test]
7196 fn gitrefspec_ref_field_name_dispatches_per_variant_onto_lifted_consts() {
7197 // The [`GitRefSpec::ref_field_name`] method routes each variant
7198 // onto the paired canonical
7199 // [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
7200 // [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] /
7201 // [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] const via a compile-
7202 // time-exhaustive match — closes the drift surface where a
7203 // future variant addition or per-arm rebrand could silently
7204 // desynchronize the YAML emit-side + human-readable narrator
7205 // consumer sites from the sub-selector-key axis. Pin the
7206 // per-variant dispatch identity so a refactor that swaps two
7207 // arms' const references silently at the method-impl site
7208 // fires as a build-time test failure, not as a
7209 // `spec.ref.<wrong-key>` reroute at cluster-apply time.
7210 assert_eq!(
7211 GitRefSpec::Tag("v0.1.0".into()).ref_field_name(),
7212 FLUX_GITREPOSITORY_REF_KEY_TAG,
7213 );
7214 assert_eq!(
7215 GitRefSpec::Branch("main".into()).ref_field_name(),
7216 FLUX_GITREPOSITORY_REF_KEY_BRANCH,
7217 );
7218 assert_eq!(
7219 GitRefSpec::Commit("deadbeef".into()).ref_field_name(),
7220 FLUX_GITREPOSITORY_REF_KEY_COMMIT,
7221 );
7222 }
7223
7224 #[test]
7225 fn gitrefspec_ref_value_extracts_underlying_scalar_per_variant() {
7226 // Peer of
7227 // [`gitrefspec_ref_field_name_dispatches_per_variant_onto_lifted_consts`]:
7228 // the [`GitRefSpec::ref_value`] method extracts the underlying
7229 // scalar the variant carries (tag / branch / commit value)
7230 // through a single collapsed match — the byte-string the
7231 // FluxCD source-controller feeds into its per-CR git-source
7232 // clone refspec. Both consumer sites in [`cluster_bundle`]
7233 // pair the sub-selector key with this scalar; pin the
7234 // per-variant extraction identity so a refactor that mixes
7235 // the arms (a spurious `.to_ascii_lowercase()` in one arm,
7236 // a lifetime-inversion that clones the payload as a scratch
7237 // `String`) surfaces as a build-time test failure.
7238 assert_eq!(GitRefSpec::Tag("v0.1.0".into()).ref_value(), "v0.1.0");
7239 assert_eq!(GitRefSpec::Branch("main".into()).ref_value(), "main");
7240 assert_eq!(
7241 GitRefSpec::Commit("deadbeef".into()).ref_value(),
7242 "deadbeef",
7243 );
7244 }
7245
7246 #[test]
7247 fn cluster_bundle_gitref_field_composes_lifted_dispatch_byte_shape() {
7248 // Fail-before-pass-after emission-side pin: the rendered
7249 // `gitrepository.yaml` document's `spec.ref` sub-block byte-
7250 // shape matches the composition of the canonical lifted
7251 // [`GitRefSpec::ref_field_name`] +
7252 // [`GitRefSpec::ref_value`] dispatch pair against the prior
7253 // inline `format!(" {arm}: {v:?}")` per-arm match block,
7254 // for every arm of the [`GitRefSpec`] discriminated-union.
7255 // Byte-identical output to the prior 3-arm inline match
7256 // (`{v:?}` on `&str` renders the same shape as `{v:?}` on
7257 // `String`) — the composition equation
7258 // `format!(" {field}: {value:?}", ...)` reduces to
7259 // `format!(" tag: {t:?}")` / `format!(" branch: {b:?}")`
7260 // / `format!(" commit: {c:?}")` per arm by construction.
7261 // Peer to the sibling
7262 // [`cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`]
7263 // emission-side pin on the tag-arm — pivots the discipline
7264 // from the tag-value axis (the prior lift closed) onto the
7265 // sub-selector-key axis (this lift closes) so the pair of
7266 // pins closes both coordinates of the `spec.ref.<key>:
7267 // <value>` sub-block.
7268 let cases = [
7269 (GitRefSpec::Tag("v0.1.0".into()), " tag: \"v0.1.0\""),
7270 (GitRefSpec::Branch("main".into()), " branch: \"main\""),
7271 (
7272 GitRefSpec::Commit("deadbeef".into()),
7273 " commit: \"deadbeef\"",
7274 ),
7275 ];
7276 for (git_ref, expected) in cases {
7277 let composed = format!(
7278 " {field}: {value:?}",
7279 field = git_ref.ref_field_name(),
7280 value = git_ref.ref_value(),
7281 );
7282 assert_eq!(
7283 composed, expected,
7284 "GitRefSpec::{git_ref:?} must compose to the prior \
7285 inline byte-shape via the lifted dispatch",
7286 );
7287 }
7288 }
7289
7290 #[test]
7291 fn cluster_bundle_gitref_narrator_composes_lifted_dispatch_byte_shape() {
7292 // Peer of
7293 // [`cluster_bundle_gitref_field_composes_lifted_dispatch_byte_shape`]
7294 // on the sibling `tag_human` narrator-prose axis in
7295 // [`cluster_bundle`] — pins the byte-shape of the `<arm>
7296 // <value>` operator-facing narrator prose the rendered
7297 // `gitrepository.yaml` document's leading `# Source — pinned
7298 // to <tag_human>` comment quotes. Byte-identical output to
7299 // the prior 3-arm inline `format!("{arm} {v}")` per-variant
7300 // match block by construction.
7301 let cases = [
7302 (GitRefSpec::Tag("v0.1.0".into()), "tag v0.1.0"),
7303 (GitRefSpec::Branch("main".into()), "branch main"),
7304 (GitRefSpec::Commit("deadbeef".into()), "commit deadbeef"),
7305 ];
7306 for (git_ref, expected) in cases {
7307 let composed = format!(
7308 "{field} {value}",
7309 field = git_ref.ref_field_name(),
7310 value = git_ref.ref_value(),
7311 );
7312 assert_eq!(
7313 composed, expected,
7314 "GitRefSpec::{git_ref:?} narrator prose must compose \
7315 to the prior inline byte-shape via the lifted dispatch",
7316 );
7317 }
7318 }
7319
7320 #[test]
7321 fn cluster_bundle_gitrepo_yaml_carries_lifted_sub_selector_keys() {
7322 // End-to-end emission-side pin: for every arm of
7323 // [`GitRefSpec`], the rendered `gitrepository.yaml` document's
7324 // `spec.ref` sub-block declares the sub-selector under the
7325 // canonical lifted [`FLUX_GITREPOSITORY_REF_KEY_TAG`] /
7326 // [`FLUX_GITREPOSITORY_REF_KEY_BRANCH`] /
7327 // [`FLUX_GITREPOSITORY_REF_KEY_COMMIT`] key — pin the presence
7328 // + value round-trip through the rendered YAML so a regression
7329 // that re-inlines the sub-selector key at the emit site
7330 // surfaces here as a test failure rather than as a silent
7331 // FluxCD source-controller sub-block reroute at reconcile
7332 // time. Peer to the sibling
7333 // [`cluster_bundle_default_git_tag_uses_lifted_caixa_core_prefix`]
7334 // pin that closes the sibling per-arm value axis on the
7335 // tag-arm.
7336 let caixa = sample_caixa();
7337 let cases: [(GitRefSpec, &str, &str); 3] = [
7338 (
7339 GitRefSpec::Tag("v0.1.0".into()),
7340 FLUX_GITREPOSITORY_REF_KEY_TAG,
7341 "v0.1.0",
7342 ),
7343 (
7344 GitRefSpec::Branch("main".into()),
7345 FLUX_GITREPOSITORY_REF_KEY_BRANCH,
7346 "main",
7347 ),
7348 (
7349 GitRefSpec::Commit("deadbeef".into()),
7350 FLUX_GITREPOSITORY_REF_KEY_COMMIT,
7351 "deadbeef",
7352 ),
7353 ];
7354 for (git_ref, expected_key, expected_value) in cases {
7355 let mut opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
7356 opts.git_ref = git_ref.clone();
7357 let files = cluster_bundle(&caixa, &opts).expect("bundle renders");
7358 let gr = files
7359 .iter()
7360 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
7361 .expect("gitrepository.yaml present");
7362 let parsed: serde_yaml::Value =
7363 serde_yaml::from_str(&gr.contents).expect("gitrepository.yaml parses as YAML");
7364 let sub_selector = parsed
7365 .get(KUBE_KEY_SPEC)
7366 .and_then(|s| s.get(FLUX_GITREPOSITORY_KEY_REF))
7367 .and_then(|r| r.get(expected_key))
7368 .and_then(|v| v.as_str())
7369 .unwrap_or_else(|| {
7370 panic!(
7371 "spec.ref.{expected_key:?} missing or non-string \
7372 for GitRefSpec::{git_ref:?}: {contents:?}",
7373 contents = gr.contents,
7374 )
7375 });
7376 assert_eq!(
7377 sub_selector, expected_value,
7378 "spec.ref.{expected_key:?} must carry the paired \
7379 scalar for GitRefSpec::{git_ref:?}",
7380 );
7381 }
7382 }
7383
7384 #[test]
7385 fn flux_helmrelease_yaml_filename_re_export_points_at_caixa_core_canonical() {
7386 // The renderer's `FLUX_HELMRELEASE_YAML_FILENAME` was lifted from
7387 // the thirteen production + test-side inline `"helmrelease.yaml"`
7388 // / `PathBuf::from("helmrelease.yaml")` /
7389 // `names.contains(&"helmrelease.yaml".to_string())` literals
7390 // across [`cluster_bundle`]'s per-`BundleFile` `HelmRelease`
7391 // document `path` emit site + every test-side round-trip
7392 // navigator that reaches into the rendered bundle by the
7393 // `HelmRelease` document filename to a re-export of
7394 // [`caixa_core::FLUX_HELMRELEASE_YAML_FILENAME`] so the Flux v2
7395 // per-cluster-bundle `HelmRelease` document filename lives in
7396 // exactly one place across every caixa renderer. Pin the equality
7397 // + `&'static` static-data identity here so any local
7398 // re-introduction of a sibling `pub const
7399 // FLUX_HELMRELEASE_YAML_FILENAME: &str = "…"` at this crate — the
7400 // canonical drift footgun where a sibling local `pub const` could
7401 // happen to carry the same string at the source while pointing
7402 // at a different `&'static` allocation — is a build-time test
7403 // failure naming the offending drift, not a silent FluxCD
7404 // `kustomize-controller` "no `HelmRelease` document found under
7405 // this bundle" reroute at cluster-side reconcile time far from
7406 // the drift site. Peer to
7407 // [`flux_key_interval_re_export_points_at_caixa_core_canonical`]
7408 // on the sibling per-CR body-key surface, and to the
7409 // [`caixa_helm::HELM_CHART_YAML_FILENAME`] (c2c99b0) /
7410 // [`caixa_helm::HELM_VALUES_YAML_FILENAME`] (9a980ba) re-exports
7411 // on the sibling Helm-chart-directory filename surfaces — pivots
7412 // the canonical-filename single-sourcing discipline from the
7413 // per-Helm-chart-directory metadata / values file axes onto the
7414 // sibling per-Flux-v2-bundle `HelmRelease` document filename
7415 // axis this crate's [`cluster_bundle`] renders.
7416 caixa_core::assert_str_reexport_identity(
7417 "FLUX_HELMRELEASE_YAML_FILENAME",
7418 FLUX_HELMRELEASE_YAML_FILENAME,
7419 caixa_core::FLUX_HELMRELEASE_YAML_FILENAME,
7420 );
7421 }
7422
7423 #[test]
7424 fn flux_gitrepository_yaml_filename_re_export_points_at_caixa_core_canonical() {
7425 // The renderer's `FLUX_GITREPOSITORY_YAML_FILENAME` was lifted
7426 // from the nine production + test-side inline
7427 // `"gitrepository.yaml"` / `PathBuf::from("gitrepository.yaml")`
7428 // / `names.contains(&"gitrepository.yaml".to_string())` literals
7429 // across [`cluster_bundle`]'s per-`BundleFile` `GitRepository`
7430 // document `path` emit site + every test-side round-trip
7431 // navigator that reaches into the rendered bundle by the
7432 // `GitRepository` document filename to a re-export of
7433 // [`caixa_core::FLUX_GITREPOSITORY_YAML_FILENAME`] so the Flux v2
7434 // per-cluster-bundle `GitRepository` document filename lives in
7435 // exactly one place across every caixa renderer. Pin the
7436 // equality + `&'static` static-data identity here so any local
7437 // re-introduction of a sibling `pub const
7438 // FLUX_GITREPOSITORY_YAML_FILENAME: &str = "…"` at this crate —
7439 // the canonical drift footgun where a sibling local `pub const`
7440 // could happen to carry the same string at the source while
7441 // pointing at a different `&'static` allocation — is a
7442 // build-time test failure naming the offending drift, not a
7443 // silent FluxCD `source-controller` "no `GitRepository`
7444 // document found under this bundle" reroute at cluster-side
7445 // reconcile time far from the drift site. Peer to
7446 // [`flux_helmrelease_yaml_filename_re_export_points_at_caixa_core_canonical`]
7447 // on the sibling per-`HelmRelease`-document filename surface —
7448 // extends the canonical-Flux-v2-bundle-filename lifted-const
7449 // discipline from the middle coordinate of the filename triple
7450 // onto its first coordinate.
7451 caixa_core::assert_str_reexport_identity(
7452 "FLUX_GITREPOSITORY_YAML_FILENAME",
7453 FLUX_GITREPOSITORY_YAML_FILENAME,
7454 caixa_core::FLUX_GITREPOSITORY_YAML_FILENAME,
7455 );
7456 }
7457
7458 #[test]
7459 fn flux_kustomization_yaml_filename_re_export_points_at_caixa_core_canonical() {
7460 // The renderer's `FLUX_KUSTOMIZATION_YAML_FILENAME` was lifted
7461 // from the sixteen production + test-side inline
7462 // `"kustomization.yaml"` /
7463 // `PathBuf::from("kustomization.yaml")` /
7464 // `names.contains(&"kustomization.yaml".to_string())` literals
7465 // across [`cluster_bundle`]'s per-`BundleFile` `Kustomization`
7466 // document `path` emit site + every test-side round-trip
7467 // navigator that reaches into the rendered bundle by the
7468 // `Kustomization` document filename to a re-export of
7469 // [`caixa_core::FLUX_KUSTOMIZATION_YAML_FILENAME`] so the
7470 // Flux v2 per-cluster-bundle `Kustomization` document filename
7471 // lives in exactly one place across every caixa renderer. Pin
7472 // the equality + `&'static` static-data identity here so any
7473 // local re-introduction of a sibling `pub const
7474 // FLUX_KUSTOMIZATION_YAML_FILENAME: &str = "…"` at this crate —
7475 // the canonical drift footgun where a sibling local `pub const`
7476 // could happen to carry the same string at the source while
7477 // pointing at a different `&'static` allocation — is a
7478 // build-time test failure naming the offending drift, not a
7479 // silent FluxCD `kustomize-controller` "no `Kustomization`
7480 // document found under this bundle" reroute at cluster-side
7481 // reconcile time far from the drift site. Peer to
7482 // [`flux_helmrelease_yaml_filename_re_export_points_at_caixa_core_canonical`]
7483 // + [`flux_gitrepository_yaml_filename_re_export_points_at_caixa_core_canonical`]
7484 // on the sibling per-`HelmRelease` / per-`GitRepository`
7485 // document filename surfaces — closes the canonical-Flux-v2-
7486 // bundle-filename lifted-const discipline on the third
7487 // coordinate of the filename triple.
7488 caixa_core::assert_str_reexport_identity(
7489 "FLUX_KUSTOMIZATION_YAML_FILENAME",
7490 FLUX_KUSTOMIZATION_YAML_FILENAME,
7491 caixa_core::FLUX_KUSTOMIZATION_YAML_FILENAME,
7492 );
7493 }
7494
7495 #[test]
7496 fn cluster_bundle_every_flux_cr_carries_lifted_flux_key_interval_scalar() {
7497 // Fail-before-pass-after pin: every rendered Flux v2 document in
7498 // the `cluster_bundle` triplet (`gitrepository.yaml`,
7499 // `helmrelease.yaml`, `kustomization.yaml`) must resolve its
7500 // `spec.interval` reconcile-poll cadence scalar under the lifted
7501 // [`FLUX_KEY_INTERVAL`] verbatim. Before the lift each of the
7502 // three sites carried an inline `interval:` literal in its
7503 // per-CR format string; a future Flux v3 rebrand on this axis (a
7504 // hypothetical upstream fluxcd/flux2 rename from `interval` to
7505 // `Interval` / `period` / `cadence` / `pollInterval` /
7506 // `reconcileInterval`, coordinated with the upstream project's
7507 // per-version deprecation cycle) without a coordinated edit at
7508 // any one of the three emit sites would have silently dropped
7509 // the per-CR reconcile schedule from the affected Flux v2
7510 // controller's per-CR watch registration — the referenced Git
7511 // source never re-polls / the referenced chart never re-templates
7512 // / the parent Kustomization never re-applies at upstream drift,
7513 // freezing the whole cluster's per-`caixa` per-cluster bundle at
7514 // the last-applied snapshot far from the rebrand commit's source.
7515 //
7516 // The pin is structural: parse each rendered YAML document in
7517 // the triplet and assert the per-CR reconcile-poll cadence
7518 // scalar-axis key resolves under the lifted constant with a
7519 // non-empty string scalar under it. A regression that re-introduces
7520 // an inline literal at any of the three emit sites surfaces as a
7521 // `None` at the lifted-const-keyed lookup on that document. Peer
7522 // to the sibling
7523 // [`cluster_bundle_helmrelease_chart_block_uses_lifted_flux_key_chart`]
7524 // /
7525 // [`cluster_bundle_helmrelease_values_block_uses_lifted_flux_key_values`]
7526 // /
7527 // [`cluster_bundle_kustomization_health_checks_block_uses_lifted_flux_key_health_checks`]
7528 // pins on the sibling per-CR body-key surfaces — extends the
7529 // canonical-Flux-v2-body-key lifted-const-keyed pin discipline
7530 // from the per-CR body-key quartet onto the sibling cross-CR-
7531 // shared reconcile-poll cadence scalar-axis this test targets.
7532 let opts = ClusterBundleOpts::for_caixa(&sample_caixa(), "rio");
7533 let files = cluster_bundle(&sample_caixa(), &opts).unwrap();
7534 for filename in [
7535 FLUX_GITREPOSITORY_YAML_FILENAME,
7536 FLUX_HELMRELEASE_YAML_FILENAME,
7537 FLUX_KUSTOMIZATION_YAML_FILENAME,
7538 ] {
7539 let doc = files
7540 .iter()
7541 .find(|f| f.path == std::path::PathBuf::from(filename))
7542 .unwrap_or_else(|| panic!("{filename} present"));
7543 let parsed: serde_yaml::Value = serde_yaml::from_str(&doc.contents)
7544 .unwrap_or_else(|_| panic!("{filename} parses as YAML"));
7545 let interval = parsed
7546 .get(KUBE_KEY_SPEC)
7547 .and_then(|s| s.get(FLUX_KEY_INTERVAL))
7548 .and_then(|v| v.as_str())
7549 .unwrap_or_else(|| {
7550 panic!(
7551 "{filename} spec.<FLUX_KEY_INTERVAL> ({FLUX_KEY_INTERVAL:?}) \
7552 scalar present; drift on this axis silently drops the \
7553 per-CR reconcile schedule from the Flux v2 controller's \
7554 per-CR watch registration",
7555 )
7556 });
7557 assert!(
7558 !interval.is_empty(),
7559 "{filename} spec.<FLUX_KEY_INTERVAL> ({FLUX_KEY_INTERVAL:?}) must \
7560 carry a non-empty duration scalar; the Flux v2 controller's \
7561 per-CR reconcile loop rejects an empty cadence at admission",
7562 );
7563 // The renderer threads opts.interval through every CR
7564 // verbatim (the same [`ClusterBundleOpts::interval`] field
7565 // for the whole per-cluster bundle); pin that the emitted
7566 // scalar agrees with the opts-side input so a future
7567 // refactor that per-CR-overrides the cadence surfaces here
7568 // rather than as a silent per-CR reconcile-schedule split.
7569 assert_eq!(
7570 interval, opts.interval,
7571 "{filename} spec.<FLUX_KEY_INTERVAL> ({FLUX_KEY_INTERVAL:?}) \
7572 must carry the same duration scalar the [`ClusterBundleOpts`] \
7573 seeded — drift here silently splits the per-CR reconcile \
7574 schedule across the three Flux v2 controllers",
7575 );
7576 }
7577 }
7578
7579 #[test]
7580 fn bundle_file_alias_resolves_to_caixa_core_rendered_file() {
7581 // Type-alias identity pin: the [`BundleFile`] alias at this
7582 // crate's boundary resolves to the canonical
7583 // [`caixa_core::RenderedFile`] the substrate-side "one rendered
7584 // leaf artifact" shape lives at. `let _: BundleFile = <a
7585 // RenderedFile>` type-checks *iff* [`BundleFile`] is the
7586 // aliased canonical (not a sibling pub-struct re-declaration
7587 // that happens to carry the same field pair — that would
7588 // compile past the struct-literal navigators below but fail
7589 // this assignment). A drifted local `pub struct BundleFile
7590 // { pub path: PathBuf, pub contents: String }` at this crate —
7591 // the canonical drift footgun that would carry the same
7592 // field pair at the source while pointing at a different
7593 // struct definition — trips this pin at caixa-flux build time
7594 // rather than surfacing as a downstream `caixa_core::RenderedFile`
7595 // consumer refusing a `BundleFile`-shaped value at type-check
7596 // time far from the drift commit.
7597 let canonical: caixa_core::RenderedFile = caixa_core::RenderedFile {
7598 path: std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME),
7599 contents: String::new(),
7600 };
7601 let aliased: BundleFile = canonical.clone();
7602 assert_eq!(aliased, canonical);
7603 // Struct-literal construction still resolves through the alias
7604 // — the pre-lift `BundleFile { path, contents }` shape at every
7605 // production emit site (three sites in [`cluster_bundle`])
7606 // continues to compile, and the derive tuple travels through
7607 // the alias.
7608 let via_alias = BundleFile {
7609 path: std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME),
7610 contents: "kind: HelmRelease\n".to_string(),
7611 };
7612 assert_eq!(
7613 via_alias.path.to_string_lossy(),
7614 FLUX_HELMRELEASE_YAML_FILENAME
7615 );
7616 }
7617
7618 #[test]
7619 fn bundle_file_new_constructor_travels_through_alias_to_canonical() {
7620 // Inherent-method-through-alias pin: the canonical
7621 // [`caixa_core::RenderedFile::new`] `impl Into<PathBuf>` /
7622 // `impl Into<String>` constructor every per-CR YAML leaf in
7623 // [`cluster_bundle`] now routes through resolves at
7624 // `BundleFile::new(…)` — Rust inherent methods travel through
7625 // a `pub type BundleFile = caixa_core::RenderedFile` alias to
7626 // the aliased canonical at name resolution, so a drifted
7627 // local `pub struct BundleFile { pub path: PathBuf, pub
7628 // contents: String }` at this crate would carry the field
7629 // pair the sibling type-alias-identity pin above still
7630 // accepts (both records share `pub path` / `pub contents`
7631 // shape) while dropping the constructor — the three sweep
7632 // sites in [`cluster_bundle`] would stop compiling and the
7633 // failing calls would name `BundleFile` directly, making the
7634 // drift-source unambiguous. This test pins the constructor's
7635 // per-alias reachability + the byte-identical record shape
7636 // against a `FLUX_GITREPOSITORY_YAML_FILENAME`-keyed probe so
7637 // the pin fires at caixa-flux build time.
7638 let via_alias_new: BundleFile =
7639 BundleFile::new(FLUX_GITREPOSITORY_YAML_FILENAME, "kind: GitRepository\n");
7640 let via_canonical_new = caixa_core::RenderedFile::new(
7641 FLUX_GITREPOSITORY_YAML_FILENAME,
7642 String::from("kind: GitRepository\n"),
7643 );
7644 assert_eq!(via_alias_new, via_canonical_new);
7645 assert_eq!(
7646 via_alias_new.path,
7647 std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME),
7648 );
7649 assert_eq!(via_alias_new.contents, "kind: GitRepository\n");
7650 }
7651
7652 #[test]
7653 fn programs_yaml_entry_name_field_routes_through_caixa_nome_accessor() {
7654 // Fail-before-pass-after pin: the emit-side `name:` scalar the
7655 // aggregator-path [`programs_yaml_entry`] writes into the
7656 // per-Servico values-schema entry at
7657 // `entry[FLEET_PROGRAMS_KEY_NAME]` must derive from the typed
7658 // [`caixa_core::Caixa::nome`] accessor byte-for-byte. Before
7659 // this converge the emit site carried a raw
7660 // `caixa.nome.clone()` field access at
7661 // [`programs_yaml_entry`]'s per-entry name-insert position —
7662 // the sole production-code `String`-carry from `Caixa::nome`
7663 // on this fn's emit path — and a future extension of the
7664 // accessor (an M4 namespace-qualified rewrite the CR
7665 // materializer applies per-CR, a per-cluster alias table
7666 // pinned through a future `:placement`-scoped slot, the
7667 // `:nome-suffix` overlay MESH-COMPOSITION §III.2 acknowledges)
7668 // that landed on the accessor but not on this emit site would
7669 // silently split the substrate-operator-side aggregator's
7670 // per-entry `name:` axis (the discriminator
7671 // [`caixa_core::upsert_named_entry`] keys off on every peer
7672 // append / replace, and the substrate operator's fleet-programs
7673 // reconciler groups per-Servico HelmRelease materialization by)
7674 // from every peer read-side consumer of `Caixa::nome`
7675 // (`lareira_chart_name` chart-directory composer,
7676 // `flux_kustomization_source_subtree` per-caixa sub-tree
7677 // composer, the error-path diagnostic
7678 // [`caixa_core::KindMismatch`] names the offending caixa's
7679 // `:nome` through). Byte-equal today (the accessor is
7680 // `&self.nome`); the pin catches any future accessor
7681 // extension whose emit-side write regresses to the raw field.
7682 // Peer to
7683 // [`caixa_mesh::tests::programs_for_aplicacao_entry_aplicacao_routes_through_caixa_nome_accessor`]
7684 // on the sibling mesh-side fleet-programs-aggregator emit
7685 // path.
7686 let caixa = sample_caixa();
7687 let entry = programs_yaml_entry(&caixa, &sample_cu_yaml()).unwrap();
7688 let emitted = entry
7689 .get(FLEET_PROGRAMS_KEY_NAME)
7690 .and_then(|n| n.as_str())
7691 .expect(
7692 "programs.yaml entry must carry a `name:` scalar — drift here \
7693 silently splits the substrate-operator-side fleet-programs \
7694 aggregator's per-entry identity from every peer read-side \
7695 consumer of `Caixa::nome`",
7696 );
7697 assert_eq!(
7698 emitted,
7699 caixa.nome(),
7700 "programs.yaml `entry[FLEET_PROGRAMS_KEY_NAME]` must derive from \
7701 the typed `caixa_core::Caixa::nome` accessor byte-for-byte — a \
7702 regression that re-inlines `caixa.nome.clone()` at the emit site \
7703 silently splits the aggregator-path per-entry `name:` axis from \
7704 every future accessor extension (namespace-qualified rewrite, \
7705 per-cluster alias table, `:nome-suffix` overlay) that lands on \
7706 the accessor",
7707 );
7708 }
7709
7710 #[test]
7711 fn cluster_bundle_gitrepository_metadata_name_routes_through_caixa_nome_accessor() {
7712 // Fail-before-pass-after pin: the emit-side `metadata.name`
7713 // scalar the bundle-path [`cluster_bundle`] writes into the
7714 // `GitRepository` CR document must derive from the typed
7715 // [`caixa_core::Caixa::nome`] accessor byte-for-byte. Before
7716 // this converge the emit site carried a raw
7717 // `let name = caixa.nome.clone()` field access at
7718 // [`cluster_bundle`]'s per-bundle name-binding position — the
7719 // sole production-code `String`-carry the fn threads into
7720 // every downstream `metadata.name` axis it emits — so a future
7721 // extension of the accessor that landed on the accessor but
7722 // not on this emit site would silently split the source-
7723 // controller-side `GitRepository` CR's per-Servico identity
7724 // (the axis the paired `HelmRelease`
7725 // `spec.chart.spec.sourceRef.name` binds through) from every
7726 // peer read-side consumer of `Caixa::nome`. Peer to
7727 // [`cluster_bundle_helmrelease_metadata_name_routes_through_caixa_nome_accessor`]
7728 // and
7729 // [`cluster_bundle_kustomization_metadata_name_routes_through_caixa_nome_accessor`]
7730 // on the sibling per-CR emit-position pins.
7731 let caixa = sample_caixa();
7732 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
7733 let files = cluster_bundle(&caixa, &opts).unwrap();
7734 let gr = files
7735 .iter()
7736 .find(|f| f.path == std::path::PathBuf::from(FLUX_GITREPOSITORY_YAML_FILENAME))
7737 .expect("gitrepository.yaml present");
7738 let parsed: serde_yaml::Value =
7739 serde_yaml::from_str(&gr.contents).expect("gitrepository.yaml parses as YAML");
7740 let emitted = kube_metadata_str_field(&parsed, KUBE_KEY_NAME).expect(
7741 "gitrepository.yaml `metadata.name` scalar present — drift here \
7742 silently orphans the source-controller-side per-Servico \
7743 GitRepository CR from every peer `spec.sourceRef.name` binding",
7744 );
7745 assert_eq!(
7746 emitted,
7747 caixa.nome(),
7748 "gitrepository.yaml `metadata.name` must derive from the typed \
7749 `caixa_core::Caixa::nome` accessor byte-for-byte — a regression \
7750 that re-inlines `caixa.nome.clone()` at the per-bundle \
7751 `let name` binding silently splits the source-controller-side \
7752 per-Servico GitRepository CR's identity from every future \
7753 accessor extension (namespace-qualified rewrite, per-cluster \
7754 alias table, `:nome-suffix` overlay) that lands on the accessor",
7755 );
7756 }
7757
7758 #[test]
7759 fn cluster_bundle_helmrelease_metadata_name_routes_through_caixa_nome_accessor() {
7760 // Fail-before-pass-after pin: the emit-side `metadata.name`
7761 // scalar the bundle-path [`cluster_bundle`] writes into the
7762 // `HelmRelease` CR document must derive from the typed
7763 // [`caixa_core::Caixa::nome`] accessor byte-for-byte. Same
7764 // single-source `let name = caixa.nome()` binding as the
7765 // peer GitRepository / Kustomization sibling pins — this test
7766 // pins the derived `HelmRelease` `metadata.name` axis (the
7767 // discriminator the Flux v2 helm-controller keys per-Servico
7768 // reconciliation off, and the axis the paired Kustomization
7769 // `spec.healthChecks[0].name` health-checks binds through).
7770 // Peer to
7771 // [`cluster_bundle_gitrepository_metadata_name_routes_through_caixa_nome_accessor`]
7772 // and
7773 // [`cluster_bundle_kustomization_metadata_name_routes_through_caixa_nome_accessor`]
7774 // on the sibling per-CR emit-position pins.
7775 let caixa = sample_caixa();
7776 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
7777 let files = cluster_bundle(&caixa, &opts).unwrap();
7778 let hr = files
7779 .iter()
7780 .find(|f| f.path == std::path::PathBuf::from(FLUX_HELMRELEASE_YAML_FILENAME))
7781 .expect("helmrelease.yaml present");
7782 let parsed: serde_yaml::Value =
7783 serde_yaml::from_str(&hr.contents).expect("helmrelease.yaml parses as YAML");
7784 let emitted = kube_metadata_str_field(&parsed, KUBE_KEY_NAME).expect(
7785 "helmrelease.yaml `metadata.name` scalar present — drift here \
7786 silently orphans the helm-controller-side per-Servico \
7787 HelmRelease CR from every peer Kustomization \
7788 `spec.healthChecks[].name` binding",
7789 );
7790 assert_eq!(
7791 emitted,
7792 caixa.nome(),
7793 "helmrelease.yaml `metadata.name` must derive from the typed \
7794 `caixa_core::Caixa::nome` accessor byte-for-byte — a regression \
7795 that re-inlines `caixa.nome.clone()` at the per-bundle \
7796 `let name` binding silently splits the helm-controller-side \
7797 per-Servico HelmRelease CR's identity from every future \
7798 accessor extension (namespace-qualified rewrite, per-cluster \
7799 alias table, `:nome-suffix` overlay) that lands on the accessor",
7800 );
7801 }
7802
7803 #[test]
7804 fn cluster_bundle_kustomization_metadata_name_routes_through_caixa_nome_accessor() {
7805 // Fail-before-pass-after pin: the emit-side `metadata.name`
7806 // scalar the bundle-path [`cluster_bundle`] writes into the
7807 // `Kustomization` CR document must derive from the typed
7808 // [`caixa_core::Caixa::nome`] accessor byte-for-byte. Same
7809 // single-source `let name = caixa.nome()` binding as the
7810 // peer GitRepository / HelmRelease sibling pins — this test
7811 // pins the derived `Kustomization` `metadata.name` axis (the
7812 // discriminator the Flux v2 kustomize-controller keys per-
7813 // Servico prune / reconcile decisions off). Peer to
7814 // [`cluster_bundle_gitrepository_metadata_name_routes_through_caixa_nome_accessor`]
7815 // and
7816 // [`cluster_bundle_helmrelease_metadata_name_routes_through_caixa_nome_accessor`]
7817 // on the sibling per-CR emit-position pins.
7818 let caixa = sample_caixa();
7819 let opts = ClusterBundleOpts::for_caixa(&caixa, "rio");
7820 let files = cluster_bundle(&caixa, &opts).unwrap();
7821 let k = files
7822 .iter()
7823 .find(|f| f.path == std::path::PathBuf::from(FLUX_KUSTOMIZATION_YAML_FILENAME))
7824 .expect("kustomization.yaml present");
7825 let parsed: serde_yaml::Value =
7826 serde_yaml::from_str(&k.contents).expect("kustomization.yaml parses as YAML");
7827 let emitted = kube_metadata_str_field(&parsed, KUBE_KEY_NAME).expect(
7828 "kustomization.yaml `metadata.name` scalar present — drift here \
7829 silently splits the kustomize-controller-side per-Servico \
7830 Kustomization CR's prune / reconcile decisions from every peer \
7831 HelmRelease CR's paired identity",
7832 );
7833 assert_eq!(
7834 emitted,
7835 caixa.nome(),
7836 "kustomization.yaml `metadata.name` must derive from the typed \
7837 `caixa_core::Caixa::nome` accessor byte-for-byte — a regression \
7838 that re-inlines `caixa.nome.clone()` at the per-bundle \
7839 `let name` binding silently splits the kustomize-controller-\
7840 side per-Servico Kustomization CR's identity from every future \
7841 accessor extension (namespace-qualified rewrite, per-cluster \
7842 alias table, `:nome-suffix` overlay) that lands on the accessor",
7843 );
7844 }
7845}