Some checks are pending
Run Check Script / check (pull_request) Waiting to run
The CRD previously accepted any string for `score.type`, so typos like `"pdoman"` or `"PodmnV0"` would be persisted by the apiserver and only surface on-device as agent-side deserialize warnings. That class of failure is distasteful and hard to debug. Replace the auto-derived schema for `ScorePayload` with a hand-rolled one that keeps the same visible shape but adds two apiserver-level guardrails: - `score.type` gets `minLength: 1` and an `x-kubernetes-validations` CEL rule requiring it to match `^[A-Za-z_][A-Za-z0-9_]*$` — a valid Rust identifier, since score variants *are* Rust struct names in `harmony::modules::podman::IotScore`. Message points operators at the concrete example `PodmanV0`. - `score.data` still carries only `x-kubernetes-preserve-unknown- fields: true`. The rule validates the discriminator's *shape*, not its *value*, so v0.3+ variants (OkdApplyV0, KubectlApplyV0) don't require an operator release — preserves ROADMAP §6.1's generic-router design. The `x-kubernetes-preserve-unknown-fields` extension stays scoped to `score.data` alone; every other field in the CRD has a strict schema, exactly one preserve-unknown-fields marker and exactly one validations block in the whole document. Smoke test extended: phase 2b applies a CR with `score.type: "has spaces"` and asserts the apiserver rejects it with the CEL message before the operator ever sees it. Positive phases (kubectl apply -> NATS KV put -> status observed -> delete -> KV key removed) still PASS end-to-end. Matches the `preserve_arbitrary` pattern used by ArgoCD (`Application.spec.source.helm.valuesObject`) and Flux (`HelmRelease.spec.values`), both of which similarly use narrow preserve-unknown-fields on a payload field without coupling the CRD to their variant catalog.