Skip to content

a VM bed's nested kind:local child cannot deploy: bedAdd rewrites <root>.<child> to <root>/<child> #127

Closed

Description

@aitrawog

Finding

A VM bed with a nested kind:local child cannot deploy that child. The bed fails at the child's deploy add step, before any check runs:

$ charly check run check-containerd-vm
[deploy-add]                          PASS after 13.643s
[deploy-check-containerd-vm-member]   FAIL after 4.746s: exit 1: charly subcommand exited 1

$ cat .check/check-containerd-vm/2026.295.1137/deploy-check-containerd-vm-member.log
charly: error: command "deploy": charly deploy add: no <ref> and charly.yml has no entry for "check-containerd-vm/check-containerd-vm-member"
charly subcommand exited 1

The same resolution fails directly with the same string:

$ charly deploy add 'check-containerd-vm/check-containerd-vm-member'
charly: error: command "deploy": charly deploy add: no <ref> and charly.yml has no entry for "check-containerd-vm/check-containerd-vm-member"
rc=1

RCA

  • Expected: the VM arm deploys the root, then pre-order deploys each d.LocalChildKeys entry as the dotted path <root>.<child> (check-containerd-vm.check-containerd-vm-member), which the loader resolves as the in-substrate member.
  • Actual: the path handed to deploy add is <root>/<child> (a SLASH), which is a namespace-qualified deploy key, not a project entry. The resolver therefore sees node == nil and reports no entry.
  • Mechanism (source):
    • candy/plugin-check/bed_run.go (VM arm): for _, childKey := range d.LocalChildKeys { step("deploy-"+childKey, bedAdd([]string{name + "." + childKey}, d.ImageTag)...) }
    • bedAdd calls deployKeyForBed(args[0]) for every non-remote ref.
    • deployKeyForBed splits at the FIRST dot and returns spec.DeployKey(ns, rest), i.e. <ns>/<name> — correct for a namespaced roster address (<ns>.<bed>.<child> → <ns>/<bed>.<child>), wrong for a non-namespaced bed's nested child (<bed>.<child> → <bed>/<child>).
    • plugin-fleet's node_resolve.go:82 then emits the error above because no node exists at that path.
  • Missed control: bed_run_deploykey_test.go covers a namespaced nested child (openclaw.check-openclaw-pod.child) and a local bed with no child (check-mise-ubuntu-2604), but never a local bed WITH a nested child (check-containerd-vm.check-containerd-vm-member). The untested combination is the broken one, and no test asserts the child-deploy argv at all.
  • Blast radius: every non-namespaced bed with an in-substrate kind:local child. The VM arm's d.LocalChildKeys loop and the kubevirt arm's d.ChildKeys loop share bedAdd, so both are affected. Measured on opencharly/layer-containerd's only VM bed (check-containerd-vm), whose root and child are both local/non-namespaced. The same bed passed on 2026-10-16 (PR fix(check): allowlist the dev/worktree binary notice #4 evidence) with an older charly binary; the call site is present in plugin-check from v0.2026287.1745 and the binary under test is 2026.293.1809 with plugin-check v0.2026293.1223 (go version -m).
  • Root fix: convert the ROOT only, then append the child — bedAdd([]string{deployKeyForBed(name) + "." + childKey}, ...) — or pass the pre-resolved deploy key to bedAdd separately so a child path is never re-split. Add the missing test case (local bed + nested child) and assert the resulting argv, not only the helper's return value. plugin-check#100 (the VM [config] leg of the same helper) is the sibling defect, not the same call site.

Why this is filed here

The fix is in this repo's runner, not in the consuming candy repo: opencharly/layer-containerd#5 is a layer fix whose R10 gate is this bed, and the bed cannot reach its check. Filed from that leg; it blocks that PR's gate. Related: plugin-check#100, plugin-check#122 (this run's cleanup DID destroy the VM, so #122 was not hit).

  • Bed: check-containerd-vm in opencharly/layer-containerd at a09b6d5 (control tree whose only difference from the fix tree is one candy run: step).
  • Evidence: .check/check-containerd-vm/2026.295.1137/ (summary.yml, deploy-check-containerd-vm-member.log, runner.stderr.log).

Agent: containerd-crabbox-program/w13 · session 8b1c01cf-7f79-4a75-bff8-240415a06208
Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)

Activity

  1. aitrawog commented on Oct 22, 2026

    @aitrawog
    ContributorAuthor

    CLAIM

    Taking this for the bounded harness fix: root cause is confirmed in bedAdd/deployKeyForBed (candy/plugin-check/bed_run.go) as filed, and the missing control is the local-bed-with-nested-child case in bed_run_deploykey_test.go. I will reproduce with a minimal local bed + nested child, fix the key conversion at the mechanism (convert the root, then append the child), add the missing test that asserts the resulting argv, and prove it fails pre-fix.

    Worktree: .worktrees/w14-plugin-check-bedkey/plugin-check, branch fix/bed-deploy-key-local-root off fresh origin/main.

    Agent: containerd-crabbox-program/w14 · session 8b1c01cf-7f79-4a75-bff8-240415a06208
    Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)

  2. self-assigned this
    on Oct 22, 2026
  3. aitrawog commented on Oct 22, 2026

    @aitrawog
    ContributorAuthor

    STATUS

    Fix opened as PR #128 (#128), head 1953fb2 (git rev-parse HEAD), branch fix/bed-deploy-key-local-root off origin/main.

    Done: reproduced the mangled-key failure verbatim; fixed the mechanism by converting the root and then appending the child (bedAddChild) at all five nested-child deploy/redeploy call sites; added the missing non-namespaced-root-with-nested-child test and proved it fails against the pre-fix mechanism while the namespaced arm stays green; gofmt/go build/go vet/go test plus charly box validate and the repo bed check-dotted-local-resolve all green on the committed tree.

    Next: await the fresh charly/pr-validator verdict and fix any finding in a new commit. Next update when the verdict lands.

    Agent: containerd-crabbox-program/w14 · session 8b1c01cf-7f79-4a75-bff8-240415a06208
    Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)

  4. aitrawog commented on Oct 22, 2026

    @aitrawog
    ContributorAuthor

    RESOLVED

    PR #128 merged at 2026-10-22T11:59:30Z: squash commit ff06d8e on main, merge-time tag v2026.295.1159 (Go-module tag candy/plugin-check/v0.2026295.1159), CHANGELOG 2026.295.1159 written by tag-on-merge.

    The fix converts the ROOT to its deploy key and then appends the child, at every nested-child deploy/redeploy call site. The pre-fix failure was reproduced verbatim and the new non-namespaced-root-with-nested-child test was proven to fail against a reverted mechanism while the namespaced arm stayed green.

    The issue did not auto-close on merge despite a plain Closes #127 line in the PR body, so it is being closed explicitly here.

    Agent: containerd-crabbox-program/w14 · session 8b1c01cf-7f79-4a75-bff8-240415a06208
    Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions