Skip to main content

caixa_core/
dialeto.rs

1//! `defcaixa` is spoken by two unrelated declarations. This module makes that
2//! a **typed fact** instead of an anonymous parse failure.
3//!
4//! # The finding
5//!
6//! Measured 2026-07-31 over the pleme-io org checkout (270 `caixa.lisp` /
7//! `*.caixa.lisp` files found with `rg --no-ignore`; a bare `rg` from the org
8//! root returns 0, which is how this stayed invisible), the corpus splits into
9//! two schemas that share zero required slots:
10//!
11//! * [`CaixaDialeto::Pacote`] — this crate's [`crate::Caixa`]. `:nome
12//!   :versao :kind :deps :bibliotecas :exe :servicos` + the supervisor/mesh
13//!   slots. It declares a **tatara-lisp package**: the thing `feira` resolves,
14//!   builds, links and publishes.
15//! * [`CaixaDialeto::Molde`] — `:name :kind :ecosystem :package {…} :workflows
16//!   […] :ci-config {…} :files […]`. It declares a **repo's generated
17//!   surface**: which foreign ecosystem (rust / go / python / …), that
18//!   ecosystem's own package metadata, the CI shims to emit, and byte-captured
19//!   file bodies. Read by `pleme-doc-gen`, never by `feira`.
20//!
21//! `:package`, `:ecosystem`, `:supports` and `:profile` have no counterpart in
22//! [`crate::Caixa`] at all — the theory doc's own D4 note records the same
23//! thing: those manifests "are authored against a schema that does not exist in
24//! Rust". They are not two spellings of one declaration. They are two domains
25//! that collided on one word, because *caixa* names a box and both are boxes.
26//!
27//! # Why this is not a bug report about broken files
28//!
29//! The Molde-dialect files are not malformed. They are correct inputs to their
30//! own consumer, and nothing in the shipped `feira` reads them, so nothing is
31//! failing today. The hazard is **latent and certain**: any new declarative
32//! surface written against "a `.caixa.lisp` is a [`crate::Caixa`]" meets a
33//! corpus where that is false for the large majority of files, and gets a flat
34//! unknown-keyword rejection that reads as "this manifest is broken" rather
35//! than "this manifest is not yours".
36//!
37//! # What this module does about it
38//!
39//! [`classify`] is total: every `(defcaixa …)` form lands in exactly one
40//! [`CaixaDialeto`], including [`CaixaDialeto::Desconhecido`] for one that
41//! matches neither. [`crate::Caixa::from_lisp`] runs it first, so a foreign
42//! dialect is [`crate::ManifestError::DialetoEstrangeiro`] — an error that
43//! names the dialect it found and the consumer that speaks it — rather than an
44//! unknown-kwarg error indistinguishable from a typo.
45//!
46//! Tier-honest: this is **parse-time rejection with a named cause**, not
47//! unrepresentability. A caller that ignores the `Err` still gets nothing
48//! useful; what it can no longer do is mistake "wrong dialect" for "bad file".
49
50use tatara_lisp::{Atom, Sexp};
51
52/// Which `(defcaixa …)` declaration a source speaks.
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
54pub enum CaixaDialeto {
55    /// This crate's [`crate::Caixa`] — a tatara-lisp package manifest.
56    /// Keyword-argument form headed by `:nome`.
57    Pacote,
58    /// `pleme-doc-gen`'s repo-surface declaration, keyword-argument form
59    /// headed by `:name` (plus `:ecosystem` / `:package`).
60    Molde,
61    /// The same declaration as [`Self::Molde`], written with the package name
62    /// as a bare positional symbol — `(defcaixa todoku-go :kind :Biblioteca
63    /// :ecosystem :go …)`. `pleme-doc-gen`'s parser reads the first token
64    /// after the head as the name, so this is one arity of one declaration,
65    /// not a third schema.
66    MoldePosicional,
67    /// A `(defcaixa …)` form matching neither. Kept as a variant rather than
68    /// an error so [`classify`] is total and a census can COUNT the residue —
69    /// a classifier that threw here would report "0 unknown" by construction.
70    Desconhecido,
71}
72
73impl CaixaDialeto {
74    /// Exhaustive iteration surface for every consumer that walks the
75    /// closed four-arm [`CaixaDialeto`] discriminator set — the
76    /// [`feira dialeto`](../../caixa_feira/cmd/dialeto/index.html)
77    /// census counter's per-arm accept-set, a future
78    /// `feira dialeto --list-dialects` CLI listing of the accepted
79    /// classifications, a future M4 `mesh.pleme.io/v1alpha1/Manifesto`
80    /// CR materializer's admission-webhook rejection body naming the
81    /// accepted-dialect set, any future census-report shape probe that
82    /// sweeps every arm to compute per-arm coverage. A future arm
83    /// addition (a fifth dialect the [`crate::dialeto`] module doc's
84    /// "third dialect" hazard actualises — the module explicitly frames
85    /// its purpose as "what stops a third dialect appearing", and this
86    /// slice is the substrate-side answer: the arm-set is one edit and
87    /// every consumer picks up the new entry by construction) extends
88    /// this slice as one edit and every downstream consumer picks up
89    /// the new entry through the shared iteration; the compiler-checked
90    /// exhaustiveness on the sibling method `match` arms
91    /// ([`Self::palavra_canonica`] / [`Self::consumidor`] /
92    /// [`Self::descricao`] / [`std::fmt::Display`]) is the build-time
93    /// guarantee that no arm forgets to grow.
94    ///
95    /// Peer of the sibling closed-set typed enums'
96    /// [`crate::CaixaKind::ALL`] (6b1f4fb) /
97    /// [`crate::aplicacao::PlacementStrategy::ALL`] (18c7342) /
98    /// [`crate::aplicacao::RateLimitUnit::ALL`] (6bce03d) /
99    /// [`crate::dep::DepList::ALL`] (45ee563) /
100    /// [`crate::supervisor::RestartStrategy::ALL`] (4eec29c) /
101    /// [`crate::supervisor::RestartPolicy::ALL`] (dd32ccf)
102    /// exhaustive-iteration surfaces — the seventh closed-set typed
103    /// enum on the caixa surface to converge onto the same
104    /// one-canonical-arm-list-per-enum discipline, and the first
105    /// dialect-classification axis (as distinct from an OTP-shape M2
106    /// slot or an M3 mesh slot) to reach it. Order matches variant
107    /// declaration order verbatim (`Pacote` → `Molde` →
108    /// `MoldePosicional` → `Desconhecido`) so the slice is the
109    /// canonical ordering every listing / rendering consumer defers to.
110    pub const ALL: &'static [Self] = &[
111        Self::Pacote,
112        Self::Molde,
113        Self::MoldePosicional,
114        Self::Desconhecido,
115    ];
116
117    /// Substrate-canonical `PascalCase` variant-name byte-string every consumer
118    /// that formats the dialect as census-facing text lands on. Returns the
119    /// per-arm `PascalCase` name of the variant (`"Pacote"` / `"Molde"` /
120    /// `"MoldePosicional"` / `"Desconhecido"`) — the one canonical
121    /// byte-string the paired [`std::fmt::Display`] impl routes through so
122    /// every downstream consumer (the `feira dialeto` census counter output
123    /// line, a future `feira dialeto --list-dialects` CLI enumeration, a
124    /// future M4 `mesh.pleme.io/v1alpha1/Manifesto` CR materializer's
125    /// admission-webhook rejection body naming the accepted-dialect set)
126    /// reaches for the same substrate primitive rather than the pre-lift
127    /// hand-rolled four-arm literal-string match every [`std::fmt::Display`]
128    /// call previously routed through in place.
129    ///
130    /// Peer of the sibling closed-set typed enums'
131    /// [`crate::CaixaKind::as_str`] / [`crate::supervisor::RestartStrategy::as_str`]
132    /// / [`crate::supervisor::RestartPolicy::as_str`] /
133    /// [`crate::aplicacao::PlacementStrategy::as_str`] /
134    /// [`crate::dep::DepList::as_str`] projections on the sibling closed-set
135    /// typed-enum discriminator axes — the seventh (and last unlifted)
136    /// closed-set fieldless typed enum on the caixa surface to converge
137    /// onto the same one-canonical-byte-string-per-arm-through-`as_str`
138    /// discipline the six siblings already carry. Unlike [`crate::CaixaKind`]
139    /// (which carries two axes: `as_str` returning lowercase Portuguese
140    /// diagnostic form vs `wire_name` returning `PascalCase` tatara-lisp
141    /// author-surface bytes), [`CaixaDialeto`] is an internal
142    /// classification with no wire surface — the `PascalCase` variant name
143    /// is the census-facing form every consumer reads, so `as_str`
144    /// suffices without a paired `wire_name` axis.
145    #[must_use]
146    pub const fn as_str(self) -> &'static str {
147        match self {
148            Self::Pacote => "Pacote",
149            Self::Molde => "Molde",
150            Self::MoldePosicional => "MoldePosicional",
151            Self::Desconhecido => "Desconhecido",
152        }
153    }
154
155    /// The keyword an author should write for this dialect, once the
156    /// migration named in [`Self::consumidor`] completes.
157    #[must_use]
158    pub const fn palavra_canonica(self) -> &'static str {
159        match self {
160            Self::Pacote => "defcaixa",
161            Self::Molde | Self::MoldePosicional => "defmolde",
162            Self::Desconhecido => "?",
163        }
164    }
165
166    /// Who reads this dialect.
167    #[must_use]
168    pub const fn consumidor(self) -> &'static str {
169        match self {
170            Self::Pacote => "caixa-core / feira",
171            Self::Molde | Self::MoldePosicional => "pleme-doc-gen",
172            Self::Desconhecido => "nobody known",
173        }
174    }
175
176    /// A one-line description for a census row or an error message.
177    #[must_use]
178    pub const fn descricao(self) -> &'static str {
179        match self {
180            Self::Pacote => "tatara-lisp package manifest (:nome :versao :kind :deps …)",
181            Self::Molde => "repo-surface declaration (:name :ecosystem :package {…} …)",
182            Self::MoldePosicional => {
183                "repo-surface declaration, positional name (defcaixa <nome> :kind …)"
184            }
185            Self::Desconhecido => "unrecognised — matches no known defcaixa schema",
186        }
187    }
188}
189
190/// [`std::fmt::Display`] routed through [`CaixaDialeto::as_str`], so the
191/// pretty-printed byte-string every consumer that formats the dialect as
192/// user-facing / census text lands on (the `feira dialeto` per-manifest
193/// `--list` row, the `feira dialeto` census summary line's per-arm
194/// counters, a future M4 admission-webhook's rejection body naming the
195/// accepted-dialect set) reaches for the same `PascalCase` per-arm
196/// byte-string the [`CaixaDialeto::as_str`] helper returns.
197///
198/// Prior to this lift the [`std::fmt::Display`] impl hand-rolled its own
199/// four-arm literal-string match — the one hand-rolled per-arm dispatch
200/// on the closed [`CaixaDialeto`] discriminator that had NO substrate
201/// primitive accessor to defer to (the sibling [`CaixaDialeto::palavra_canonica`] /
202/// [`CaixaDialeto::consumidor`] / [`CaixaDialeto::descricao`] projections
203/// carry distinct byte-shapes per axis, so none of them could serve as
204/// the Display source). A future variant addition (a fifth dialect the
205/// module doc's "third dialect" hazard actualises) would land one arm at
206/// the enum and per-arm returns at the paired accessors, but a hand-rolled
207/// [`std::fmt::Display`] match would silently drop the new arm to compile-
208/// fail-at-the-match-arm-site rather than through the shared substrate
209/// primitive. Routing [`std::fmt::Display`] through [`CaixaDialeto::as_str`]
210/// closes the last unlifted per-arm `PascalCase`-name projection on the
211/// caixa surface — the seventh (and last unlifted) closed-set fieldless
212/// typed enum on the caixa surface to converge onto the same
213/// `Display`-through-`as_str` discipline the six siblings
214/// ([`crate::CaixaKind`] / [`crate::supervisor::RestartStrategy`] /
215/// [`crate::supervisor::RestartPolicy`] /
216/// [`crate::aplicacao::PlacementStrategy`] / [`crate::aplicacao::RateLimitUnit`]
217/// / [`crate::dep::DepList`]) already carry.
218impl std::fmt::Display for CaixaDialeto {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        f.write_str(self.as_str())
221    }
222}
223
224/// A source that is not a `(defcaixa …)` / `(defmolde …)` form at all.
225#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
226pub enum DialetoError {
227    #[error("source has no top-level form")]
228    Vazio,
229    #[error("top-level form is not a list — a manifest is `(defcaixa …)`")]
230    NaoEhLista,
231    #[error(
232        "top-level form is headed by `{encontrado}`, not `defcaixa` or `defmolde` \
233         (a manifest's first form must be the declaration itself)"
234    )]
235    CabecaErrada { encontrado: String },
236    #[error("manifest does not parse as tatara-lisp: {0}")]
237    Leitura(String),
238}
239
240/// Classify a manifest source without committing to either schema.
241///
242/// Deliberately reads only the head symbol and the set of top-level keywords —
243/// enough to route, never enough to half-parse. A classifier that started
244/// validating would grow into a third parser, which is the shape of the problem
245/// it exists to name.
246///
247/// # Errors
248/// [`DialetoError`] when the source is not a manifest declaration at all.
249pub fn classify(src: &str) -> Result<CaixaDialeto, DialetoError> {
250    let forms = tatara_lisp::read(src).map_err(|e| DialetoError::Leitura(e.to_string()))?;
251    let first = forms.first().ok_or(DialetoError::Vazio)?;
252    classify_form(first)
253}
254
255/// [`classify`] over an already-read form.
256///
257/// # Errors
258/// [`DialetoError`] when the form is not a manifest declaration.
259pub fn classify_form(form: &Sexp) -> Result<CaixaDialeto, DialetoError> {
260    let list = form.as_list().ok_or(DialetoError::NaoEhLista)?;
261    let head = list
262        .first()
263        .and_then(Sexp::as_symbol)
264        .ok_or(DialetoError::NaoEhLista)?;
265
266    match head {
267        // `defmolde` is unambiguous by construction — it exists precisely so a
268        // consumer never has to infer which declaration it holds. Both arities
269        // are the same declaration; the positional one keeps its own variant
270        // only so a census can report the split.
271        "defmolde" => {
272            return Ok(if starts_with_positional_name(&list[1..]) {
273                CaixaDialeto::MoldePosicional
274            } else {
275                CaixaDialeto::Molde
276            });
277        }
278        "defcaixa" => {}
279        other => {
280            return Err(DialetoError::CabecaErrada {
281                encontrado: other.to_string(),
282            });
283        }
284    }
285
286    let args = &list[1..];
287
288    // `(defcaixa <symbol> :kind … :ecosystem …)`. Only the Molde dialect has a
289    // positional arity; `Caixa` is keyword-only, so a leading bare symbol
290    // settles it without looking further.
291    if starts_with_positional_name(args) {
292        return Ok(CaixaDialeto::MoldePosicional);
293    }
294
295    let keys = top_level_keywords(args);
296    let has = |k: &str| keys.iter().any(|s| s == k);
297
298    // Order matters, and it is not arbitrary: `:nome` and `:name` are the two
299    // required head slots and no file in the measured corpus carries both.
300    // Checking them FIRST means the decision rests on the one slot each schema
301    // makes mandatory, rather than on optional evidence like `:ecosystem`.
302    if has("nome") {
303        return Ok(CaixaDialeto::Pacote);
304    }
305    if has("name") || has("ecosystem") || has("package") {
306        return Ok(CaixaDialeto::Molde);
307    }
308    Ok(CaixaDialeto::Desconhecido)
309}
310
311/// True when the first argument is a bare symbol rather than a keyword — the
312/// positional-name arity.
313fn starts_with_positional_name(args: &[Sexp]) -> bool {
314    matches!(args.first(), Some(Sexp::Atom(Atom::Symbol(_))))
315}
316
317/// The top-level keyword names (without the leading `:`) of a kwarg list.
318///
319/// Steps in pairs so a keyword appearing as a VALUE — `:kind :Biblioteca`, or a
320/// nested `(:nome "dep" :versao "^0.1")` inside `:deps` — is never counted as a
321/// top-level slot. A naive scan for `:nome` anywhere in the source classifies
322/// every Molde manifest with a `:deps` list as a Pacote.
323fn top_level_keywords(args: &[Sexp]) -> Vec<String> {
324    let mut out = Vec::new();
325    let mut i = 0;
326    while i < args.len() {
327        if let Sexp::Atom(Atom::Keyword(k)) = &args[i] {
328            out.push(k.clone());
329            i += 2;
330        } else {
331            i += 1;
332        }
333    }
334    out
335}
336
337#[cfg(test)]
338mod tests {
339    use super::*;
340
341    const PACOTE: &str = r#"
342      (defcaixa
343        :nome   "checkout"
344        :versao "0.1.0"
345        :kind   Servico
346        :deps   ((:nome "caixa-teia" :versao "^0.1")))
347    "#;
348
349    const MOLDE: &str = r#"
350      (defcaixa
351        :name "base64"
352        :kind :Biblioteca
353        :ecosystem :rust-single-crate
354        :package {:name "base64" :version "0.22.1"}
355        :workflows [:auto-release])
356    "#;
357
358    const MOLDE_POSICIONAL: &str = r#"
359      (defcaixa todoku-go
360        :kind :Biblioteca
361        :ecosystem :go
362        :package {:name "todoku-go" :version "0.3.0"})
363    "#;
364
365    #[test]
366    fn the_package_dialect_is_recognised() {
367        assert_eq!(classify(PACOTE), Ok(CaixaDialeto::Pacote));
368    }
369
370    #[test]
371    fn the_repo_surface_dialect_is_recognised() {
372        assert_eq!(classify(MOLDE), Ok(CaixaDialeto::Molde));
373    }
374
375    #[test]
376    fn the_positional_arity_is_recognised() {
377        assert_eq!(
378            classify(MOLDE_POSICIONAL),
379            Ok(CaixaDialeto::MoldePosicional)
380        );
381    }
382
383    #[test]
384    fn defmolde_classifies_without_inference() {
385        // The whole point of the new keyword: no schema sniffing required.
386        let src = r#"(defmolde :name "x" :kind :Biblioteca :ecosystem :go)"#;
387        assert_eq!(classify(src), Ok(CaixaDialeto::Molde));
388        let pos = r"(defmolde todoku-go :kind :Biblioteca :ecosystem :go)";
389        assert_eq!(classify(pos), Ok(CaixaDialeto::MoldePosicional));
390    }
391
392    #[test]
393    fn a_nested_nome_does_not_make_a_repo_surface_look_like_a_package() {
394        // The exact failure a substring scan produces: `:deps ((:nome …))`
395        // contains `:nome`, but not as a top-level slot.
396        let src = r#"
397          (defcaixa
398            :name "x"
399            :ecosystem :rust-single-crate
400            :deps ((:nome "inner" :versao "^0.1")))
401        "#;
402        assert_eq!(classify(src), Ok(CaixaDialeto::Molde));
403    }
404
405    #[test]
406    fn a_keyword_in_value_position_is_not_a_slot() {
407        // `:kind :Biblioteca` — the value is itself a keyword. Stepping one at
408        // a time would read `:Biblioteca` as a top-level slot.
409        let src = r#"(defcaixa :kind :Biblioteca :name "x")"#;
410        assert_eq!(classify(src), Ok(CaixaDialeto::Molde));
411    }
412
413    #[test]
414    fn an_unrecognised_defcaixa_is_reported_not_guessed() {
415        let src = r#"(defcaixa :licenca "MIT")"#;
416        assert_eq!(classify(src), Ok(CaixaDialeto::Desconhecido));
417    }
418
419    #[test]
420    fn a_form_that_is_not_a_manifest_is_an_error_not_a_dialect() {
421        assert_eq!(
422            classify("(defflake :nome \"x\")"),
423            Err(DialetoError::CabecaErrada {
424                encontrado: "defflake".into()
425            })
426        );
427        assert_eq!(classify(""), Err(DialetoError::Vazio));
428    }
429
430    #[test]
431    fn every_dialect_names_its_consumer_and_its_canonical_keyword() {
432        // Guards the routing table itself: a new variant added without an arm
433        // here is a compile error in the match, and a variant that claims
434        // `defcaixa` while being read by pleme-doc-gen would re-open the
435        // collision this module closes. Sweeps [`CaixaDialeto::ALL`] rather
436        // than the pre-lift open-coded four-arm literal list — a future arm
437        // addition extends the slice as one edit and this pin picks it up
438        // by construction.
439        for &d in CaixaDialeto::ALL {
440            assert!(!d.descricao().is_empty(), "{d}");
441            assert!(!d.consumidor().is_empty(), "{d}");
442        }
443        assert_eq!(CaixaDialeto::Pacote.palavra_canonica(), "defcaixa");
444        assert_eq!(CaixaDialeto::Molde.palavra_canonica(), "defmolde");
445        assert_ne!(
446            CaixaDialeto::Pacote.palavra_canonica(),
447            CaixaDialeto::Molde.palavra_canonica(),
448            "the two dialects must not share a canonical keyword — that IS the defect"
449        );
450    }
451
452    #[test]
453    fn caixa_dialeto_all_enumerates_every_variant_exactly_once() {
454        // Three-legged exhaustiveness pin, peer of the sibling
455        // `caixa_kind_all_enumerates_every_variant_exactly_once`
456        // (caixa-core/src/kind.rs) /
457        // `restart_strategy_all_enumerates_every_variant_exactly_once`
458        // (caixa-core/src/supervisor.rs) shape.
459        //
460        // 1. arm-count invariant: `ALL.len()` matches the declared arm
461        //    count (four — a fifth arm added without extending `ALL`
462        //    fails this pin at caixa-core test time);
463        // 2. pairwise-distinctness invariant: every variant appears at
464        //    most once in the slice (a duplicate arm would silently
465        //    double-count in the census consumer, so the pin rejects
466        //    duplicates outright);
467        // 3. coverage invariant: every literal `CaixaDialeto::X` is in
468        //    the slice (the compiler-checked exhaustiveness on the peer
469        //    per-arm `match self` in the accessors keeps the enum arm
470        //    set and the `ALL` slice mutually aligned).
471        assert_eq!(
472            CaixaDialeto::ALL.len(),
473            4,
474            "ALL must list every arm exactly once; a fifth arm added \
475             without extending ALL fails this pin — extend ALL alongside \
476             the new variant"
477        );
478
479        let mut seen: Vec<CaixaDialeto> = Vec::new();
480        for &d in CaixaDialeto::ALL {
481            assert!(
482                !seen.contains(&d),
483                "ALL contains a duplicate arm: {d}. Every variant appears \
484                 exactly once — a duplicate would double-count in every \
485                 iteration consumer"
486            );
487            seen.push(d);
488        }
489
490        // Coverage: exhaustively assert every literal variant is somewhere
491        // in the slice. Written as an exhaustive `match` so a future arm
492        // addition fails to compile here (missing match arm) until the
493        // corresponding `assert` is added — the compiler enforces the pin's
494        // completeness rather than a hand-maintained variant list.
495        for variant in [
496            CaixaDialeto::Pacote,
497            CaixaDialeto::Molde,
498            CaixaDialeto::MoldePosicional,
499            CaixaDialeto::Desconhecido,
500        ] {
501            let coverage_probe = match variant {
502                CaixaDialeto::Pacote
503                | CaixaDialeto::Molde
504                | CaixaDialeto::MoldePosicional
505                | CaixaDialeto::Desconhecido => variant,
506            };
507            assert!(
508                CaixaDialeto::ALL.contains(&coverage_probe),
509                "ALL is missing variant {coverage_probe} — extend the slice"
510            );
511        }
512    }
513
514    #[test]
515    fn caixa_dialeto_all_is_const_and_matches_iteration_count() {
516        // Pins the const-ness of the slice at const-fold time. A future
517        // change that promoted `ALL` to a non-const initializer (a lazy-
518        // static, a runtime-computed Vec) would fail to compile here —
519        // the pin locks in the compile-time-known iteration surface
520        // every consumer builds against. Peer of the sibling
521        // `caixa_kind_all_is_const_and_matches_iteration_count` (kind.rs)
522        // / `restart_strategy_all_is_const_and_matches_iteration_count`
523        // (supervisor.rs) shape.
524        const ALL: &[CaixaDialeto] = CaixaDialeto::ALL;
525        assert_eq!(ALL.len(), CaixaDialeto::ALL.len());
526        // Sweep the iterator without collapsing to `.len()` so a future
527        // change to `ALL`'s carrier that decouples `.len()` from the
528        // iteration count (a lazy-computed shape, an alias `impl Iterator`
529        // return, a wrapper newtype) still passes here iff the two agree
530        // arm-for-arm; the `#[allow]` opts this local pin out of the
531        // clippy `iter_count` collapse that would defeat the intent.
532        #[allow(clippy::iter_count)]
533        let iterated = ALL.iter().count();
534        assert_eq!(iterated, CaixaDialeto::ALL.len());
535    }
536
537    #[test]
538    fn caixa_dialeto_all_covers_every_variant_by_display_probe() {
539        // Fanning `Display` over the slice sweeps the paired accessors
540        // ([`CaixaDialeto::palavra_canonica`] / [`CaixaDialeto::consumidor`]
541        // / [`CaixaDialeto::descricao`]) at every arm — every returned
542        // byte-string is non-empty (the accessors' contract). A future
543        // arm added without extending its per-arm `match self` return
544        // would compile-fail at the accessor call inside the loop;
545        // together with the `ALL.len() == 4` pin above, this locks the
546        // accessor arm-set and the `ALL` slice mutually.
547        for &d in CaixaDialeto::ALL {
548            let display_form = d.to_string();
549            assert!(
550                !display_form.is_empty(),
551                "Display must render a non-empty byte-string for every \
552                 arm; empty: {d:?}"
553            );
554            // Consumidor / descricao / palavra-canonica must each surface
555            // a non-empty scalar; every downstream diagnostic consumer
556            // reaches through these accessors.
557            assert!(!d.palavra_canonica().is_empty(), "{d}");
558            assert!(!d.consumidor().is_empty(), "{d}");
559            assert!(!d.descricao().is_empty(), "{d}");
560        }
561    }
562
563    #[test]
564    fn caixa_dialeto_as_str_returns_pascal_case_variant_name() {
565        // Fail-before-pass-after per-arm shape pin: the four
566        // [`CaixaDialeto::as_str`] arms must return the canonical
567        // `PascalCase` byte-string that names the variant. Pre-lift this
568        // byte-string existed only inside the hand-rolled Display impl's
569        // four-arm literal-string match — every consumer that wanted the
570        // `PascalCase` name reached through `format!("{d}")`'s allocation
571        // path. Pinning the four arms explicitly here refuses a future
572        // regression that ever reroutes an arm to a distinct spelling
573        // (`"pacote"` lowercase, `"MoldePositional"` English rebrand,
574        // `"Unknown"` for `Desconhecido`) — the census output and the
575        // typed accessor would silently disagree until a downstream
576        // consumer surfaced the drift at census time. Peer of the sibling
577        // [`crate::supervisor::tests::restart_strategy_variants_serialize_to_lifted_scalar_values`]
578        // / `placement_strategy_variants_serialize_to_lifted_scalar_values`
579        // / `caixa_kind_as_str_returns_lifted_peer_const` shape on the
580        // sibling closed-set typed-enum discriminator axes — the seventh
581        // (and last unlifted) closed-set typed enum on the caixa surface
582        // to converge onto the same per-arm-shape-pin discipline.
583        for (variant, expected) in [
584            (CaixaDialeto::Pacote, "Pacote"),
585            (CaixaDialeto::Molde, "Molde"),
586            (CaixaDialeto::MoldePosicional, "MoldePosicional"),
587            (CaixaDialeto::Desconhecido, "Desconhecido"),
588        ] {
589            assert_eq!(
590                variant.as_str(),
591                expected,
592                "CaixaDialeto::{variant:?}.as_str() must return the \
593                 canonical `PascalCase` variant-name byte-string; drift here \
594                 splits the census-facing text from the substrate \
595                 primitive every downstream consumer will read"
596            );
597        }
598    }
599
600    #[test]
601    fn caixa_dialeto_display_routes_through_as_str_helper() {
602        // Fail-before-pass-after convergence pin: for every arm in
603        // [`CaixaDialeto::ALL`], the [`std::fmt::Display`] rendered form
604        // must byte-equal [`CaixaDialeto::as_str`]'s return value. Pre-
605        // lift these two paths were structurally independent — the
606        // Display impl hand-rolled its own four-arm literal-string
607        // match with no compile-time link back to any substrate accessor
608        // — so a future variant rename could land at `Display` without
609        // touching a paired accessor (or vice versa), silently splitting
610        // the two paths on the renamed arm. Pinning the byte-equality
611        // here makes any such split a caixa-core build-time failure at
612        // this test rather than surfacing far from the rename commit as
613        // a downstream census consumer emitting one spelling while the
614        // typed accessor returned another. Peer of the sibling
615        // [`crate::kind::tests::caixa_kind_display_routes_through_as_str_helper`]
616        // (which pins the same convergence on the [`crate::CaixaKind`]
617        // closed-set axis) — extends the discipline onto the seventh
618        // (and last unlifted) closed-set fieldless typed enum on the
619        // caixa surface.
620        for &variant in CaixaDialeto::ALL {
621            assert_eq!(
622                variant.to_string(),
623                variant.as_str(),
624                "CaixaDialeto::{variant:?} Display must route through \
625                 CaixaDialeto::as_str (single source of truth: the \
626                 lifted per-arm `PascalCase` variant-name byte-string)"
627            );
628        }
629    }
630
631    #[test]
632    fn caixa_dialeto_as_str_is_const_fn() {
633        // Const-context pin: [`CaixaDialeto::as_str`] must remain
634        // `const fn` (its match arms return `pub const` byte-strings, so
635        // no non-const operation exists on the resolution path).
636        // Downstream consumers reaching for the accessor from a `const`
637        // context (a future substrate-wide const-fold-driven audit table
638        // that materializes every dialect's census label at build time,
639        // a per-arm CR-admission-webhook message registration in a
640        // `const` gate) rely on the const-ness. A future accidental
641        // downgrade to non-`const` (an added runtime helper reachable
642        // only from a non-`const` context, a manual hand-rolled `impl`
643        // that shadows this method) trips at caixa-core build time
644        // rather than surfacing as a downstream `const`-context
645        // regression far from the accessor declaration. Peer of the
646        // sibling [`crate::kind::tests::caixa_kind_wire_name_is_const_fn`]
647        // pin on the paired [`crate::CaixaKind`] byte-string axis.
648        const PACOTE: &str = CaixaDialeto::Pacote.as_str();
649        const MOLDE: &str = CaixaDialeto::Molde.as_str();
650        const MOLDE_POSICIONAL: &str = CaixaDialeto::MoldePosicional.as_str();
651        const DESCONHECIDO: &str = CaixaDialeto::Desconhecido.as_str();
652        assert_eq!(PACOTE, "Pacote");
653        assert_eq!(MOLDE, "Molde");
654        assert_eq!(MOLDE_POSICIONAL, "MoldePosicional");
655        assert_eq!(DESCONHECIDO, "Desconhecido");
656    }
657}