From 02b2256f8055ef180cb1556737e416a6ddbd3b6d Mon Sep 17 00:00:00 2001 From: Andreas Trawoeger Date: Sat, 26 Sep 2026 14:48:06 +0200 Subject: [PATCH 1/3] fix(scaffold): correct the repo scaffold copied from the plugin-jetkvm template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three defects, each found by auditing against the org's actual conventions rather than copying a template: 1. .github/workflows/ci.yml DELETED. It was copied from plugin-jetkvm and referenced candy/plugin-jetkvm/go.mod|go.sum (a path that does not exist here), so every gate step would fail on a non-existent module. Beyond the wrong path: a repo-local workflow enforces nothing org-wide — the org ruleset requires EXACTLY ONE check (validate / validate) and FORBIDS per-repo rulesets (org-ruleset.sh verify fails if one survives), so a repo-local workflow is advisory-only. The R10 gate for a plugin repo is its own disposable bed (cua-verb-probe), not a repo ci.yml. 6 of 7 plugin repos ship no ci.yml; the closest analogue (plugin-kubevirt, a Go module with tests and a vendored client) has none. 2. deploy.yml pin v2026.258.0219 -> v2026.269.1034. The load-time schema gate (sdk/loaderkit/load_unified.go GateSchemaVersion) requires the pinned charly's HEAD schema to EXACTLY equal the config's version:. The old pin's HEAD schema is 2026.249.2125 while this repo's charly.yml is 2026.261.1747, so the copied pin FAILS with 'config schema 2026.261.1747 is newer than this charly supports (max 2026.249.2125)' — verbatim the failure plugin-jetkvm's deploy.yml hits on its own main today. v2026.269.1034 is a release whose HEAD schema IS 2026.261.1747. 3. .gitignore extended with the canonical charly-generated-artifact patterns (.check/, .containerignore, .dockerignore, .build/, migration backups). Proven live with the corrected pin's charly built from the pinned tag: $ /tmp/pinproof/bin/charly box validate charly box validate: OK — checked 1 candy, 2 deploys, 7 distros, 7 builders; 0 warnings, 0 errors *Assisted-by: OpenCode ollama-cloud DeepSeek V4.1 Flash (fully tested and validated)* --- .github/workflows/ci.yml | 50 ------------------------------------ .github/workflows/deploy.yml | 2 +- .gitignore | 18 +++++++++++++ 3 files changed, 19 insertions(+), 51 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 49a3464..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,50 +0,0 @@ -# The Go gates for this plugin's own module. -# -# The stock plugin repos carry no Go CI (their candies were thin); THIS one -# ships a real Go module with a vendored device client, so the rulebook's -# "tests that can fail" (R7) requires a gate that actually runs them: -# gofmt, the configured golangci-lint set, the formatter-class diff, -# go vet, and the unit tests (which drive a fake JetKVM device). -name: ci - -on: - push: - branches: [main] - pull_request: - workflow_dispatch: - -concurrency: - group: ci-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - go: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - - - uses: actions/setup-go@v5 - with: - go-version-file: candy/plugin-jetkvm/go.mod - cache-dependency-path: candy/plugin-jetkvm/go.sum - - - name: gofmt - working-directory: candy/plugin-jetkvm - run: test -z "$(gofmt -l .)" - - - name: golangci-lint - uses: golangci/golangci-lint-action@v7 - with: - version: v2.13.2 - working-directory: candy/plugin-jetkvm - - - name: go vet - working-directory: candy/plugin-jetkvm - run: go vet ./... - - - name: go test - working-directory: candy/plugin-jetkvm - run: go test ./... diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f229461..ce070f2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -22,7 +22,7 @@ jobs: - name: Fetch the pinned charly source (CI-time temp checkout) run: | - git clone --depth 1 --branch v2026.258.0219 https://github.com/opencharly/charly.git /tmp/charly + git clone --depth 1 --branch v2026.269.1034 https://github.com/opencharly/charly.git /tmp/charly - uses: actions/setup-go@v5 with: diff --git a/.gitignore b/.gitignore index 32494b0..764600c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,20 @@ +# Build output /bin/ *.test + +# charly run artifacts +.check/ + +# Go workspace files — this is a STANDALONE module (charly's loader builds it +# with GOWORK=off), so a workspace file here would only mask module resolution. +go.work +go.work.sum + +# charly-generated build context ignores + build output +.containerignore +.dockerignore +.build/ + +# Migration rollback backups (charly migrate writes .bak.) +*.bak +*.bak.* From 5f2eeede559d332cd941a5ea2ce5bce72f6f1edc Mon Sep 17 00:00:00 2001 From: Andreas Trawoeger Date: Sat, 26 Sep 2026 14:57:32 +0200 Subject: [PATCH 2/3] fix(ci): repair the Go gate (repoint, don't delete) + the dead code it caught MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review round: deleting ci.yml was WRONG. My first-principles test answered 'is a repo-local check REQUIRED by the org?' (no) and wrongly concluded about the real question — 'does it RUN this repo's tests?' (yes: this repo ships a real Go module + 8 unit tests, and nothing else runs them; deploy.yml checks only the manifest, the bed only verb dispatch). A test gate's purpose is to run THIS repo's tests. So ci.yml is REPAIRED: go-version-file/cache-dependency-path/working-directory repointed from candy/plugin-jetkvm (a path that does not exist here) to candy/plugin-cua, and the JetKVM prose replaced with this repo's real rationale. Running the repaired gate then caught TWO REAL DEFECTS it is designed to catch — dead code (R5), invisible because nothing was running golangci-lint: - client.go: unused hostname() helper ('a small helper for evidence rows'), zero callers, removed with its now-unused 'os' import. - kind.go: unused kindCapability() helper — a redundant DUPLICATE (R3) of the inline {Class: "kind", Word: "cua", InputDef: "#CuaDeviceInput"} already advertised in plugin.go:46; removed. The gate now runs green end to end (the exact ci.yml steps): gofmt -l . -> clean go vet ./... -> clean golangci-lint run -> 0 issues go test ./... -> ok github.com/opencharly/plugin-cua/candy/plugin-cua And the plugin still serves + validates: charly box validate -> OK, 0 warnings. *Assisted-by: opencode ollama-cloud/deepseek-v4.1-flash (fully tested and validated)* --- .github/workflows/ci.yml | 51 ++++++++++++++++++++++++++++++++++++++ candy/plugin-cua/client.go | 7 ------ candy/plugin-cua/kind.go | 10 -------- 3 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..13bacea --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,51 @@ +# The Go gates for this plugin's own module. +# +# This repo ships a REAL Go module (the cua provider + its client, CUE schema, and +# unit tests), so the rulebook's "tests that can fail" (R7) requires a gate that +# actually RUNS them: gofmt, golangci-lint, go vet, and the unit tests. The candy +# manifest gate (deploy.yml `charly box validate`) checks the manifest, not the Go +# code, and the bed exercises verb DISPATCH, not the unit tests — so this workflow +# is the only place the module's tests run. +name: ci + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + go: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - uses: actions/setup-go@v5 + with: + go-version-file: candy/plugin-cua/go.mod + cache-dependency-path: candy/plugin-cua/go.sum + + - name: gofmt + working-directory: candy/plugin-cua + run: test -z "$(gofmt -l .)" + + - name: golangci-lint + uses: golangci/golangci-lint-action@v7 + with: + version: v2.13.2 + working-directory: candy/plugin-cua + + - name: go vet + working-directory: candy/plugin-cua + run: go vet ./... + + - name: go test + working-directory: candy/plugin-cua + run: go test ./... diff --git a/candy/plugin-cua/client.go b/candy/plugin-cua/client.go index c65a07f..5c19596 100644 --- a/candy/plugin-cua/client.go +++ b/candy/plugin-cua/client.go @@ -16,7 +16,6 @@ import ( "context" "encoding/json" "fmt" - "os" "strings" "github.com/opencharly/plugin-cua/candy/plugin-cua/params" @@ -111,9 +110,3 @@ func jsonArgs(m map[string]any) string { func shellSingleQuote(s string) string { return "'" + strings.ReplaceAll(s, "'", `'\''`) + "'" } - -// hostname is a small helper for evidence rows. -func hostname() string { - h, _ := os.Hostname() - return h -} diff --git a/candy/plugin-cua/kind.go b/candy/plugin-cua/kind.go index c7a2378..4e3aeb8 100644 --- a/candy/plugin-cua/kind.go +++ b/candy/plugin-cua/kind.go @@ -106,16 +106,6 @@ func applyDeviceDefaults(in *params.CuaInput, dev *params.CuaDeviceInput) { } } -// kindCapability advertises the plugin's kind:cua capability — the entity's -// self-contained CUE schema, served over the same Describe channel as the verb. -func kindCapability() sdk.ProvidedCapability { - return sdk.ProvidedCapability{ - Class: "kind", - Word: kindWord, - InputDef: "#CuaDeviceInput", - } -} - // deviceCanonicalJSON is the OpLoad body decode: the host validates the authored entity // against #CuaDeviceInput, then this re-marshals it canonically. func deviceCanonicalJSON(paramsJSON []byte) (json.RawMessage, error) { From 6d5738ef659bab4a8e6359f3892488c694ac1de9 Mon Sep 17 00:00:00 2001 From: Andreas Trawoeger Date: Sat, 26 Sep 2026 14:58:59 +0200 Subject: [PATCH 3/3] docs: re-freeze the PR body against the final head The body was rewritten for the corrected approach (repair the Go gate, not delete it; the two dead-code findings it caught). The validator keys to the head SHA and reads the body THEN, so this empty commit re-triggers a run keyed to a head whose body is already final. *Assisted-by: opencode ollama-cloud/deepseek-v4.1-flash (fully tested and validated)*