Repository navigation
feat(plugin): compose each served unit's schema, then unify it onto the base - #1115
Conversation
…he base opencharly/sdk#490's second ordered root. The host's plugin schema gate joined every loaded unit's served text into ONE compilation unit and compiled it onto the base. That shape cannot carry an import: a plugin that imports github.com/opencharly/spec/schema gets its import clause copied into a file that already has one, and CUE refuses before resolution is even attempted ("expected label or ':', found 'STRING'"). It made the one-unit case refuse the import outright too, because the text compile had no module in scope. Each unit is now COMPOSED as its own CUE module instance (spec/schemacompose — the ONE composer, in the contract module, because this host may import spec and may not import the sdk, while the serve side may import both) and unified onto the running value. The unit boundary lands where CUE's own package boundary is: one package per plugin. The running value is grown one unify per registration instead of being rebuilt from the base per registration. That is not cosmetic: rebuilding made loading quadratic, and it was MEASURED here — charly/charly's TestMain, which registers the 63 builtin plugin schemas, went from 1.4 s to 26.4 s, which in turn pushed a cancellation test past its 10 s bound (TestConnectPluginReady_HonorsACallerCancellation: the fixture's child process could not finish its own TestMain and answer the handshake). With one unify per registration TestMain is 1.1 s and that test passes at 1.45 s. The declarations the gate reads per source (topLevelDefNames, the charly#770 collision identity index) are unchanged; the def names now come from the composed unit value, which carries the same top-level definitions. Assisted-by: DeepSeek Harness deepseek-v4.1-flash (fully tested and validated)
validator INCONCLUSIVE — no review verdict was produced (not a BLOCK; no code finding)The gate could not obtain a review verdict on this run, so it produced no code finding. This is not a BLOCK and the PR is not being rejected — but the required check stays RED on purpose: unreviewed code must never merge.
Root cause (measured in this run). Durable remedy.
Thread policy. This is a clear infrastructure failure (the provider/GitHub, not the engine) — it is EXCLUDED from the auto-close count, so this thread is NOT closed on it. Fix any A run that produced no verdict keeps this required check RED: unreviewed code must never merge. Full diagnostics: this run's evidence artifact + job log (not embedded here — embedding a runaway log would feed it into the next review and deepen the collapse). |
3 similar comments
validator INCONCLUSIVE — no review verdict was produced (not a BLOCK; no code finding)The gate could not obtain a review verdict on this run, so it produced no code finding. This is not a BLOCK and the PR is not being rejected — but the required check stays RED on purpose: unreviewed code must never merge.
Root cause (measured in this run). Durable remedy.
Thread policy. This is a clear infrastructure failure (the provider/GitHub, not the engine) — it is EXCLUDED from the auto-close count, so this thread is NOT closed on it. Fix any A run that produced no verdict keeps this required check RED: unreviewed code must never merge. Full diagnostics: this run's evidence artifact + job log (not embedded here — embedding a runaway log would feed it into the next review and deepen the collapse). |
validator INCONCLUSIVE — no review verdict was produced (not a BLOCK; no code finding)The gate could not obtain a review verdict on this run, so it produced no code finding. This is not a BLOCK and the PR is not being rejected — but the required check stays RED on purpose: unreviewed code must never merge.
Root cause (measured in this run). Durable remedy.
Thread policy. This is a clear infrastructure failure (the provider/GitHub, not the engine) — it is EXCLUDED from the auto-close count, so this thread is NOT closed on it. Fix any A run that produced no verdict keeps this required check RED: unreviewed code must never merge. Full diagnostics: this run's evidence artifact + job log (not embedded here — embedding a runaway log would feed it into the next review and deepen the collapse). |
validator INCONCLUSIVE — no review verdict was produced (not a BLOCK; no code finding)The gate could not obtain a review verdict on this run, so it produced no code finding. This is not a BLOCK and the PR is not being rejected — but the required check stays RED on purpose: unreviewed code must never merge.
Root cause (measured in this run). Durable remedy.
Thread policy. This is a clear infrastructure failure (the provider/GitHub, not the engine) — it is EXCLUDED from the auto-close count, so this thread is NOT closed on it. Fix any A run that produced no verdict keeps this required check RED: unreviewed code must never merge. Full diagnostics: this run's evidence artifact + job log (not embedded here — embedding a runaway log would feed it into the next review and deepen the collapse). |
Review — PASSHead SHA: Security screen: PASS (no scope mismatch; version pin bump justified by opencharly/spec#297; no secrets/egress; gate preserved — self-containment becomes "composes on its own", still rejects an undeclared base-def reference; no alias growth; no Checklist: All applicable rules PASS or NA. Code gate matches the core-plugin-loading class: fresh Placement: CORRECT — plugin schema loading stays in core (plugin loading is core); the shared composer correctly lands in Comment thread: empty (0 comments) — nothing to disposition. Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
Review — BLOCKHead SHA: Change class: code/config — core plugin-loading (per-unit compose) plus cross-module Blocks
Comments considered
Non-blocking notes
Verdict: BLOCK ollama-cloud/deepseek-v4.1-flash — action-review. |
validator INCONCLUSIVE — no review verdict was produced (not a BLOCK; no code finding)The gate could not obtain a review verdict on this run, so it produced no code finding. This is not a BLOCK and the PR is not being rejected — but the required check stays RED on purpose: unreviewed code must never merge.
Root cause (measured in this run). Durable remedy.
Thread policy. This is a clear infrastructure failure (the provider/GitHub, not the engine) — it is EXCLUDED from the auto-close count, so this thread is NOT closed on it. Fix any A run that produced no verdict keeps this required check RED: unreviewed code must never merge. Full diagnostics: this run's evidence artifact + job log (not embedded here — embedding a runaway log would feed it into the next review and deepen the collapse). |
Review — PASSHead SHA: Security screen: PASS — no scope mismatch (all 13 files accounted for); no secrets/egress; guardrail preserved (self-containment becomes "composes on its own", still hard-rejects an undeclared base-def reference, pinned by Comments considered:
Non-blocking notes: Verdict: PASS ollama-cloud/deepseek-v4.1-flash — action-review. |
Summary
opencharly/sdk#490's second ordered root: the host's plugin schema gate no longer joins unit
sources into one compilation unit.
compileBasePlusServedcompiledstrings.Join(everyLoadedUnit, "\n")onto charly's base, andregisterPluginUnitSchemafirst compiled each unit's text standalone with no CUE module inscope. Both shapes are text, and text cannot carry the import this cutover exists for. Measured
on the pre-change tree, with a plugin schema that imports
github.com/opencharly/spec/schema:The second is a failure #490 names as independent of the first: N units joined into one file
put N import clauses in one compilation unit, which is not CUE at all.
Now each unit is COMPOSED as its own CUE module instance and the values are unified onto the
base — the unit boundary lands exactly where CUE's own package boundary is: one package per
plugin. The composer is
spec/schemacompose, the ONE composer in the contract module: this hostmay import
github.com/opencharly/specand may NOT importgithub.com/opencharly/sdk(thisrepo's import-purity gate, "the sdk mechanism kits and the sdk root plugin-authoring package are
for PLUGINS to import, never the host"), while the serve side may import both — so the shared
home is the only place the two halves can judge the same schema with the same code.
The running value is grown one unify per registration, not rebuilt from the base. That is a
measured requirement, not a refinement: rebuilding made plugin loading quadratic, and
charly/charly's TestMain — which registers the 63 builtin plugin schemas — went from 1.4 s to26.4 s, which then pushed
TestConnectPluginReady_HonorsACallerCancellationpast its 10 s bound,because the fixture's child process could not finish its own TestMain and answer the handshake.
With one unify per registration TestMain is 1.1 s and that test passes at 1.45 s.
The declarations the gate reads per source are unchanged:
topLevelDefNamesnow reads thecomposed unit's value, which carries the same top-level definitions, and the charly#770
collision identity index is untouched.
The composer's deep arms live where the composer lives: opencharly/spec#297 tagged
v0.2026313.453, which this change pins.Files
charly/plugin_loader.gocharly/plugin_schema_import_test.gocharly/plugin_schema_collision_test.gocharly/provider_checkenv_schema_gate_test.gocharly/registry_testsupport_test.gocharly/go.modgithub.com/opencharly/spec→v0.2026313.453charly/go.sumThe six lockstep
tools/modulesThe
gojob'sTestContractPinsMatchSharedrequires every locksteptools/*module to carry the shared pins.Bumping spec in
charly's owngo.modwithout them fails that test — caught by CI, not by a localgo test ./...,which never leaves the
charly/module. Fixed with the repo's owncharly task mods-tidy, which changed exactlythese six files (spec pin
v0.2026313.48across the lockstep set):tools/generate-packages/go.modtools/generate-packages/go.sumtools/golden-cloudinit/go.modtools/golden-cloudinit/go.sumtools/golden-compile/go.modtools/golden-compile/go.sumHow tested
Code gate, on the committed tree
d481eb65609feb27bce4694a7fe95fc5211e937d:The suite includes
TestMain, which loads all 63 builtin plugin schemas through the changedgate — so the whole shipped corpus composes and unifies under the new shape.
The host's own arms:
R7 — the arms fail without the change. With
origin/main'splugin_loader.gorestored, thesame source produced the two errors quoted in the Summary (
imported but not definedfor oneunit;
expected label or ':', found 'STRING'for two joined). That measurement is the reason thejoined path cannot simply be given a module.
R9 — the binary is the source.
./scripts/bootstrap-charly.shbuilt this worktree'sbin/charly(charly version=2026.313.0209), and the changed path ran live:R10 — the disposable bed.
./bin/charly check run check-pod-overlayon this tree (adisposable: truepod bed that builds an overlay image, deploys it, runs its checks, does agenuine
charly updaterebuild and re-checks). The first attempt failed on an upstreamcurl: (22) The requested URL returned error: 504fetching a release tarball inside the image build — an external condition, RCA'd and evidenced before retrying. The retry's summary:summary.ymlrecords the same run against the worktree binary:driver: .../dsh-490/charly/bin/charly,driver_version: 2026.313.0209, every stepok: true.