schema

package
v0.2026268.2152 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 25, 2026 License: MIT Imports: 1 Imported by: 0

README

spec/schema — the single-source CUE schema

Every charly.yml shape (box / candy / vm / kubernetes / deploy / …) is defined ONCE here, in package-less *.cue files. These files are the single source of truth for two consumers:

  1. Runtime validation (ingress). The schema travels WITH this module as schema.FS (package github.com/opencharly/spec/schema). charly core (charly/cue_schema.go sharedCueSchema) unifies every schema/*.cue file via schemaconcat.ConcatSchema (sorted, newline-joined) into ONE compiled cue.Value, and validates every loaded entity against its #<Kind> def. See /charly-build:validate.
  2. Generated Go param types + vocabulary (spec). charly task cue-gen turns these same files into the committed spec/*_gen.go — so the Go structs the loader decodes into, and the kind/verb/method word lists the CLI dispatches on, can never drift from what the schema validates.

The package-less files MUST stay package-less — ConcatSchema concatenates them into one scope. The package spec clause + the file-level @go(spec) attribute that cue exp gengotypes needs are injected by the gen pipeline (internal/schemagen -mode=concat), NEVER written into the source.

Regenerating spec — charly task cue-gen

In THIS repository:

charly task cue-gen

The task is cue-gen in this repo's charly.yml (the kind: task surface). It depends on bootstrap-cue + wire-gen (which in turn depends on bootstrap-protoc):

  1. Bootstraps the pinned cue CLI into ./bin/cue (gitignored) — v0.16.1, the SAME version as charly's embedded cuelang.org/go library, so the CLI that runs gengotypes matches the library that compiles the schema. It downloads the checksum-pinned release tarball (a no-op once ./bin/cue is at the pinned version).
  2. Concatenates schema/*.cue via internal/schemagen -mode=concat (the SAME schemaconcat.ConcatSchema contract as the runtime sharedCueSchema — one concatenation contract), headed package spec + @go(spec).
  3. cue exp gengotypes → spec/cue_types_gen.go (the Go param structs).
  4. internal/schemagen -mode=vocab → spec/vocab_gen.go (KindWords, DocDirectives, StepKeywords, ContextWords, OpFields, OpVerbs, AuthoringVerbs, … — all read straight from the compiled schema via the cue API), and -mode=version → spec/version_gen.go (the schema-version consts from schema/version.cue).
  5. gofmt the committed generated files.

wire-gen (chained first) additionally renders protocol/schema/*.cue into proto/plugin.proto and compiles the Go gRPC stubs.

Each plugin's OWN params/cue_types_gen.go is generated from its self-contained candy/plugin-*/schema/*.cue in the plugin's OWN repository, via the SAME internal/schemagen + pinned cue pipeline (R3). The former superproject taskfiles/Cue.yml wrapper — which chained this repo's cue:gen and then looped over each plugin — was removed with the candy de-submodule work (charly#452, merged 2026-08-29); plugin param generation now lives with the plugin.

The spec task rename (cue:gen → cue-gen) has no cross-repo consumer: the superproject wrapper that once invoked spec/Taskfile.yml's cue:gen no longer exists on charly's origin/main (verified: git -C charly ls-tree -r origin/main --name-only | grep -c taskfiles/Cue.yml → 0).

These runs are reproducible: two consecutive charly task cue-gen invocations produce no diff, and TestGenReproducible (in spec/) fails CI if the committed *_gen.go differs from a fresh regeneration. Never hand-edit the *_gen.go files — change the *.cue source and regenerate.

The @go(...) annotations

cue exp gengotypes is lossy: every CUE disjunction degrades to any / map[string]any / an empty struct (Go cannot express a disjunction), and field names get a naive leadingCap + underscores-preserved mapping. Two annotation classes in the *.cue source fix this — both are inert for runtime validation (CUE attributes never participate in unification):

  • Field renames — @go(<GoName>) makes the generated Go field name match the hand-written charly param struct (http → HTTP, cap_add → CapAdd, kernel-param → KernelParam, …). The wire (JSON/YAML) key is preserved.
  • Union-type suppression + redirect — the handful of disjunction defs whose faithful Go shape charly relies on are annotated @go(-) (suppressing the lossy generated type) and hand-written in spec/union_types.go (the SAME package, so the generated structs reference them by name). The current set is the source itself: grep schema/*.cue for @go(-) and read the matching hand-written types in spec/union_types.go — an enumerated copy here would drift. A scalar-containing disjunction is suppressed with a trailing value attribute — (…) @go(-) — so {} & string can never collapse the validation; an all-struct disjunction takes a bare trailing @go(-).

Egress schemas

The egress schemas (the CUE charly validates the config it WRITES against) do NOT live here. They live in the superproject's compiled-in candy/plugin-egress/egress-schemas/ (+ vendor/cloud_config.cue), with candy/plugin-deploy/egress.go as a thin shim — see /charly-internals:egress. So schema/*.cue here is purely the INGRESS schema; only the node.cue node-disjunction grammar defs appear as (harmless) generated types in cue_types_gen.go (excluded from param-gen by excludeParamGen).

Documentation

Overview

Package schema exports the CUE schema source as an embedded FS — the single runtime origin for charly core's sharedCueSchema, the loader's base-schema splice, and the dev-time spec generation. The schema and the Go types generated from it (package spec) live in ONE module so the reproducibility gate (TestGenReproducible) is a single-repo check.

Index

Constants

This section is empty.

Variables

FS holds every *.cue schema file at the FS root (no directory prefix). Consumers concatenate it via schemaconcat.ConcatSchema(FS, ".", nil).

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL