pub fn is_chart_description_shape(s: &str) -> Result<(), String>Expand description
Predicate: assert that s is a valid chart-description shape.
The :descricao axis is a free-form prose summary that lands in
the rendered lareira-<nome> Helm chart’s Chart.yaml
description: field (a YAML scalar consumed by helm list,
helm search, Artifact Hub, and every chart-aware UI) and in
the chart’s README.md header paragraph
(caixa-helm/src/lib.rs:232, caixa-helm/src/lib.rs:333).
The contract — modeled on the YAML 1.2 plain-style scalar
grammar and the Helm chart spec’s expectation that
description: is a one-line summary:
- 1..=
CHART_DESCRIPTION_MAX_LEN(512) bytes; - no leading whitespace (paste-from-aligned-doc footgun —
YAML plain-style scalars round-trip trim-and-restore on
leading whitespace, so an authored
" foo"lands as"foo"in the rendered Chart.yaml and the round-trip back throughcaixa.lispsilently drops the space); - no trailing whitespace (paste-from-doc footgun — every YAML
dumper trims trailing whitespace from plain-style scalars,
so an authored
"foo "round-trips inconsistently); - no ASCII control characters anywhere (
0x00..=0x1Fplus0x7FDEL) — tabs, newlines, carriage returns, and every other control byte break the single-line YAML scalar shape and the README header paragraph. The newline / CR arms are the canonical paste-from-multiline-doc footgun; the tab arm is the canonical paste-from-aligned-doc footgun; the other-control-byte arm catches every more-exotic paste-from-binary-blob shape (0x00NUL,0x07BEL,0x1BESC) that would silently land in the renderedChart.yamlas a YAML-illegal byte sequence and fail athelm linttime far from the source caixa.lisp; - non-ASCII bytes (UTF-8 continuation sequences) are
accepted — the canonical author shapes (
"Canonical Rust→wasm32-wasip2 caixa Servico.","FIXME — describe this caixa") carry→(U+2192) and—(U+2014) and every downstream consumer (YAML 1.2, Helm v3, every chart-aware UI) round-trips Unicode losslessly; - no Unicode bidirectional-override / isolate format
codepoints (U+202A
LRE, U+202BRLE, U+202CPDF, U+202DLRO, U+202ERLO, U+2066LRI, U+2067RLI, U+2068FSI, U+2069PDI) — the nine codepoints UAX #9 names as the structural prerequisite of the “Trojan Source” attack class (CVE-2021-42574 / Boucher & Anderson 2021) that flip the rendered visual order of every following character until a matching pop. Routed through the lifted [find_unicode_bidi_override] helper so the same nine-codepoint accepted set is shared withis_chart_maintainer_name_shapeon the sibling YAML-plain-style-scalar surface, structurally consistent. The non-ASCII byte arm above admits Unicode letters / em-dash / arrows because YAML 1.2 + Helm v3 + every chart-aware UI round-trip them losslessly; the bidi-override codepoints break that round-trip discipline by class (the byte sequence rides verbatim into the renderedChart.yaml’sdescription:value but renders differently inhelm show chart/ Artifact Hub /helm listvs the author’s editor view ofcaixa.lisp), defeating the THEORY.md §V.2 render-determinism contract every typed slot carries on the same axis the per-byte CR/LF/control arms above close for ASCII. - no non-ASCII Unicode line-break codepoints (U+0085
NEL, U+2028LS, U+2029PS) — the three codepoints UAX #14 (Unicode Line Breaking Algorithm) and the YAML 1.1 §4.1 b-char production both treat as line terminators outside the ASCII\n/\rarms above. YAML 1.2 §5.4 retired them per UTR #20, so YAML 1.2-strict parsers preserve them verbatim while YAML 1.1 parsers (go-yaml v2 which Helm v3 / kubectl link,ruamel.yamlin compat mode) split the scalar on them — the same:descricaovalue parses as single-line through one consumer and multi-line through another, breaking cross-parser determinism on the same axis the per-byte\n/\rarms close for ASCII. Independently, every UAX #14 conformant text consumer (editors, terminals,helm list/ Artifact Hub web UIs) breaks the visual line at these codepoints regardless of YAML version, so the author’s editor view ofcaixa.lispand the chart-consumer’s rendered view diverge even when both YAML parsers agree on the byte-level shape. Routed through the lifted [find_unicode_line_break] helper so the same three-codepoint accepted set is shared withis_chart_maintainer_name_shape, peer of the [find_unicode_bidi_override] lift on the same two predicates one trajectory earlier. - no Unicode invisible-format codepoints (U+00AD
SHY, U+200BZWSP, U+2060WJ, U+2061FAFUNCTION APPLICATION, U+2062ITINVISIBLE TIMES, U+2063ISINVISIBLE SEPARATOR, U+2064IPINVISIBLE PLUS, U+FEFFZWNBSP/ BOM) — the eight BMP Cf-category zero-width codepoints with no visible glyph in any conforming font. The author’s editor view ofcaixa.lispand the chart- consumer’shelm list/ Artifact Hub description column agree on the visible glyph sequence ("Canonical Servico"and"Canonical\u{200B}Servico"render identically), but the byte sequence the YAML-plain-style-scalar carries verbatim differs — every byte-level grep / diff / equality comparison and the Artifact Hub description-search index lookup disagree silently with the visible-glyph match. Closes the canonical paste-from-Microsoft-Word (SHY auto- inserted at hyphenation candidates), paste-from-text- editor-saved-as-UTF-8-with-BOM (leading BOM byte), paste-from-typesetting-doc (ZWSP / WJ invisible word-break hints), and paste-from-MathJax/LaTeX-rendered-formula (FUNCTION APPLICATION / INVISIBLE TIMES / INVISIBLE SEPARATOR / INVISIBLE PLUS — the four math-formula invisible operators MathJax / LaTeX export between adjacent symbols for screen-reader operator semantics) footguns. Routed through the lifted [find_unicode_invisible_format] helper so the same eight-codepoint accepted set is shared withis_chart_maintainer_name_shape, third lift in the UAX-driven render-determinism trio (peer of [find_unicode_bidi_override] on the visual-order axis and [find_unicode_line_break] on the single-line/multi- line axis). The eight-codepoint set excludes U+200CZWNJ/ U+200DZWJ(legitimate compositional load in Indic / Persian scripts and emoji ZWJ sequences) and U+200ELRM/ U+200FRLM(legitimate single-character direction hints in mixed-script prose); the visible-order risk on bidi overrides — not marks — is closed by the prior helper.
The predicate is a structural floor — it enforces the
single-line printable-UTF-8 shape every realistic chart
description carries, not a per-byte alphabet check (which would
regress every non-ASCII canonical fixture). Same trajectory as
is_spdx_expression_shape (the ASCII-alphabet floor on the
:licenca axis) and is_git_repo_url (the URL-shape floor on
the :repositorio axis): the typed validator refuses the
downstream consumer’s would-also-refuse shapes at the source
caixa.lisp boundary with the offending value named verbatim.
Returns the parser-shaped reason on rejection (without wrapping
in any error variant) so each per-axis caller —
crate::Caixa::validate_descricao for the universal
:descricao axis at validate time, every future per-description
axis (a future Aplicacao-level :descricao summary axis on
mesh.pleme.io/v1alpha1/Caixa CRs, a future Servico-level
per-:contratos edge :descricao annotation) — wraps the same
reason in its own typed *Invalid { <axis>, reason } variant.
The reason wording is axis-agnostic (“chart descriptions reject
leading whitespace”) so every call site reading the same
diagnostic points at the same rule; drift between any two axes’
rule enforcement is a build error visible at this predicate, not
a per-renderer “this passed validate but helm lint rejected
the Chart.yaml description: value” surprise.
Empty input is rejected here (defensively) and at each call
site via the narrower crate::ManifestError::DescricaoEmpty
variant — the same empty-first cascade is_dns_1123_label,
is_gateway_api_http_path, is_wit_world_ref,
is_nats_subject, is_wasi_keyvalue_slot,
is_git_ref_name, is_git_oid, is_git_repo_url,
is_cargo_feature_name, and is_spdx_expression_shape all
carry.
§Errors
Returns the parser-shaped reason naming the specific violation
(length / leading-whitespace / trailing-whitespace /
tab / newline / carriage-return / other-control-byte /
Unicode-bidi-override-codepoint / Unicode-line-break-codepoint),
without wrapping in any error variant — every caller maps the
same String into its own typed *Invalid { <axis>, reason }
enum variant.