Repository navigation
feat(schemaparams): generate params in-process over the offline compose - #299
Conversation
Replace the `cue exp gengotypes` shell-out with charly's own CUE-Go-API generator, loaded through schemacompose's offline module registry, so a plugin schema that imports github.com/opencharly/spec/schema projects to the Go package that owns the shapes (github.com/opencharly/spec/spec). - schemacompose exports ComposeText and Instance, so the ONE compose now feeds the serve side, the host gate and the Go projection from the same module instance and the same offline resolution. - schemaparams/gotypes.go ports gengotypes v0.16.1's mapping in-process. A schema without an import stays byte-identical: the pinned-CLI oracle in the tests compares byte for byte, and the committed spec tree regenerates as a no-op. Doc-comment canonicalization is done locally so Go 1.26 and Go 1.27 emit one form. - schemaparams/gohome.go carries the CUE-package to Go-package relation that closes F2; an import with no registered Go home is a loud error. - cue-gen no longer bootstraps the cue CLI: the CLI leaves the generation leg entirely and remains the pinned authoring tool for `cue eval ./schema`. Generate(dir, pkg) replaces Generate(dir, pkg, cueDir); the consumer call site in opencharly/plugin-candy is the next leg of opencharly/opencharly#950. Closes #298. Updates #271. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
Review — PASSHead SHA: Security screen: PASS — no injection directives, no secrets, no added egress, no weakened guardrails (the CLI is removed from the generation leg, a net reduction); no scope mismatch (all 16 files accounted for in the body). Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
The compile arm built its temp module from a minimal `require spec` and
`-mod=mod`, so `go build` expanded the module graph and asked the proxy for
gopkg.in/check.v1's go.mod — which CI's cache did not hold, and GOPROXY=off
refused the lookup:
go: gopkg.in/yaml.v3@v3.0.1 requires
gopkg.in/check.v1@v0.0.0-...: module lookup disabled by GOPROXY=off
It passed locally only because this host's cache happened to hold that go.mod.
The temp module now mirrors this module's own declaration (same go directive,
same requirement set, module path rewritten, contract module added as a local
replace) and builds in the default readonly mode, so no graph expansion is
attempted. Reproduced with a cold cache minus check.v1: the old construction
fails with the CI error, the new one passes.
Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
Review — PASSHead SHA: Security screen: PASS — no injected directives, no secrets/egress, no new deps; the shell-out to the checksum-pinned CLI is removed from the generation leg (net reduction), the pin/fetcher is preserved for authoring/tests, and no security machinery (validator spec, rulebook, hooks, branch protection) is touched. Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
… generation leg (#13) spec#299 replaced the `cue exp gengotypes` shell-out with an in-process CUE-Go-API generator. `schemaparams.Generate` now takes (schemaDir, pkg); the cueDir argument and `GenerateWithCue*` are gone. - params.go: call the two-argument Generate, delete cueCacheDir and the cuetoolchain import. The verb's own wiring (path derivation, write-on-change no-op, --check) is unchanged. - params_test.go: the pipeline stub and the real-pipeline arm follow the new signature. Generation is in-process, so the provisioning skip is deleted and a failure is a failure rather than a visible skip. - .agents/skills/candy/SKILL.md and the paramsUsage text: the schema is composed and generated in-process (no cue CLI, no checkout, no toolchain provisioning); the pinned cue CLI remains the authoring tool for schema sources. - go.mod/go.sum: spec v0.2026281.933 -> v0.2026313.1428 (tag v0.2026313.1428 contains merge 9428017f). The spec bump also requires sdk v0.2026280.2246 -> v0.2026309.2334, the version charly already pins: the older sdk's vmshared aliases reference spec types removed by the intervening schema changes, so the module does not compile against the new spec without it. Refs opencharly/spec#299, opencharly/opencharly#950, opencharly/opencharly#945. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
Summary
spec/schemaparamsno longer shells out tocue exp gengotypes. The schema directory is concatenated as before, then composed as ONE CUE module instance throughschemacompose— the same offlineload.Config+ registry the serve side and the host gate already use — and the Go params are generated in-process from the CUE Go API. Generation and composition now share one resolution path, and thecueCLI leaves the generation leg entirely.Both measured failures in #298 are closed:
schemacomposegained an exportedComposeTextthat returns the loaded module instance, so the projection composes through the ONE offline registry instead of writing a scratch module and shelling out. A plugin schema carryingimport "github.com/opencharly/spec/schema"now loads against the contract module the Go binary already links: no published CUE module, no module cache, nocuebinary.github.com/opencharly/spec/schemamaps togithub.com/opencharly/spec/spec(schemaparams/gohome.go). An import with no registered Go home is a loud error, never a reference to a path that may not compile.The generator (
schemaparams/gotypes.go) is a faithful in-process port ofcue exp gengotypesv0.16.1 — that package is INTERNAL tocuelang.org/go, which is why the CLI was shelled out to — so a schema without an import generates byte-identically; both directions are proved below. The one thing not delegated to the local formatter is doc-comment canonicalization: Go 1.27'sgo/printerstopped rewriting a struct field's doc comment, so leaving it to the toolchain would make the same schema regenerate differently on a 1.27 developer box and in the 1.26 CI. The transform now uses the publicgo/doc/commentparser, and generation is byte-identical under both Go 1.26.8 and Go 1.27.3.The committed
spec/cue_types_gen.gois unchanged: a clean regeneration is a no-op, andTestGenReproduciblenow compares bytes on every run (it no longer skips when the CLI is absent). The next leg of opencharly/opencharly#950 is the consumer call site in opencharly/plugin-candy (see Change classification); the census is opencharly/opencharly#945.Head
20baf6439660df9f1d69e1625c4da71b11cac0e5.How tested
Every command below ran from the spec worktree on the committed tree (
git status --shortempty) at Head20baf6439660df9f1d69e1625c4da71b11cac0e5.The gate this repo's CI declares
No-import case: byte-identical to the pinned
cue exp gengotypesThe oracle inside
schemaparams_test.gore-runs the old recipe verbatim with the pinned CLI (concat, scratch module,cue exp gengotypes, tag normalization) and the test compares the two outputs byte for byte:The same comparison outside the test, on the plugin-tunnel twin shape (no import), plus the two-toolchain comparison (go1.27.3 output vs go1.26.8 output):
/tmp/pr-evidence/twin-inproc.goisschemaparams.Generate;/tmp/pr-evidence/twin-gengotypes.gois the pinned CLI's output on the same source./tmp/ev127and/tmp/ev126hold the same generated files from the two toolchains.spec's own generation: clean regeneration is a no-op
The real blocked case: plugin-tunnel's import shape generates usable Go
The fixture is the prior measurement's shape B (
schemaparams/testdata/import/schema/tunnel.cue):import "github.com/opencharly/spec/schema", the twins#TunnelConfig/#TunnelPortdeleted,#TunnelInputreferencingschema.#TunnelConfig. The generated file, and the build of it in a module that requires this one:Coverage added by this change
Update after the first CI run: the compile arm's module graph
The first CI run failed the
gojob inTestGenerateImportCompiles(verdict PASS on the code; this was a test-harness defect). RCA: the temp module was declared with a minimalrequire specand built with-mod=mod, sogo buildtried to EXPAND the module graph and asked the proxy forgopkg.in/check.v1's go.mod, which CI's cache did not hold;GOPROXY=offrefused the lookup. It passed locally only because this host's cache happened to hold that go.mod. The missed control was the arm's own declaration: a consumer module has a COMPLETE requirement set, not a minimal one. The arm now mirrors this module's declaration (same go directive and requirement set, module path rewritten, contract module added as a local replace) and builds in the default readonly mode, so no expansion is attempted. Reproduced with a cold cache minuscheck.v1:Rulebook compliance
git-workflow,go,pluginandstrict-policy, plus this repo'sAGENTS.mdand the umbrella rulebook read fromgit show origin/main.go/printergainedtok != token.IDENTin its doc-comment rewrite gate, so struct-field doc comments were no longer canonicalized; the missed control was an arm comparing the new generator against the CLI. The fix canonicalizes doc comments in-process withgo/doc/comment, and the oracle arm plus the two-toolchain comparison hold the line. (2) The first CI run'sgojob failed in the compile arm's temp-module declaration (RCA and cold-cache reproduction above); the fix mirrors the module's own declaration so no graph expansion is attempted. No finding is deferred; the lint reports 0 issues.schemacompose.composeServedBody, shared byServedSchema,ServedTextandComposeText), one generator, one tag normalizer, and one CUE-to-Go relation (goHomes); no second resolver was written.schema/README.md,charly.ymland the package docs describe the shipped behaviour.schema/README.md:origin/main(20f14cf5e383ed284b3d579fb47f7f09b9209eb9),git status --shortwas empty before each commit, and the branch is pushed for a pull request only: no force-push, no direct push tomain.go build, not a string assertion), re-proved against a cold module cache.go.moddeclares.charly/pr-validatoris the merge gate.Change classification
schemaparams.Generate(schemaDir, pkg, cueDir)becomesGenerate(schemaDir, pkg),GenerateExcludingloses itscueDirargument, and theGenerateWithCuepair is deleted. The one call site iscandy/plugin-candy/params.goin opencharly/plugin-candy, whoseparamsPipeline(schemaDir, pkg, cueDir)call and CLI-provisioning help text change with its pin bump — the next leg of the producer-first sequence in design: a duplicate row retires only with the composition — the one-home half of D-PAT-2 is a mirror the text splice forces opencharly#950. Nothing in this repo consumes the removed surface.spec/cue_types_gen.goandspec/vocab_gen.goare byte-identical to the committed files; a schema without an import generates exactly what it generated before.github.com/opencharly/spec/specand references its types, instead of importing the CUE package path whose Go package exports onlyFS.schema/README.mdstates that reading.cueCLI is off the generation leg, not out of the repo.bootstrap-cuestays as the pinned tool for authoring the schema as a module (cue eval ./schema);cue-genno longer depends on it.schemaparams.Filed issues
opencharly/spec#298— closed by this change: both measured failures (F1 resolution, F2 owning package) are fixed and proved above.opencharly/spec#271— updated: Direction 1 (the in-process generator for params) landed; the grammar-table generator and the retirement ofschemaretagand the hand mirrors remain.opencharly/opencharly#950— updated: the projection leg is unblocked; theplugin-candycall site is the next unit. Census: design: the D-PAT-1..3 schema-pattern gate lands green over a census of known violations, which must reach zero opencharly#945.Closes #298. Updates #271.
Files changed
charly.ymlcue-genno longer depends onbootstrap-cue; comments describe the in-process generation and the remaining authoring role of the CLIcue.mod/module.cuego.modlibrary pincuetoolchain/cuetoolchain.gointernal/cuesetup/main.gointernal/schemagen/main.goschema/README.mdgengotypesmentions explained as the mapping the port reproducesschemacompose/compose.goComposeTextandInstance; the one compose now feeds the projection tooschemaconcat/schemaconcat.goschemaparams/gohome.goschemaparams/gotypes.gocue exp gengotypesv0.16.1 with local doc-comment canonicalizationschemaparams/schemaparams.goschemaparams/schemaparams_test.goschemaparams/testdata/import/schema/tunnel.cueschemaparams/testdata/twin/schema/tunnel.cueschemaretag/schemaretag.goschemaparamsas its callerspec/gen_repro_test.goAssisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)