Repository navigation
Description
Problem
A disposable pod bed invoked QUALIFIED from the umbrella cannot deploy: prepare-venue asks build:generate resolve for the bed's slash-form deploy key as if it were a BOX name, so the deploy dies at unknown box "charly/check-sidecar-pod" before any container exists.
This is the same site as plugin-build#28 (sdk/deploykit/graph.go:312, FilterBox), but not the same string as the one #28 fixed.
Measured
charly check run charly.check-sidecar-pod from the umbrella root, 2026-11-03:
[vm-build-check-sidecar-pod-ephvm] PASS 3m45.933s
[image-build] PASS 10m59.609s
[check-image] PASS 2m0.379s
[deploy-add] FAIL 20m45.57s: exit 1
charly: error: command "deploy": deploy-dispatch add: deploy plugin: deploy-dispatch add:
prepare venue: InvokeProvider deploy:pod op=prepare-venue:
plugin-deploy-pod prepare-venue: build-generate-resolve:
build generate resolve: scoping generation to requested boxes:
unknown box "charly/check-sidecar-pod"
Why this differs from #28
#28 reported unknown box "openclaw" — a bare NAMESPACE, and it was fixed in opencharly/plugin-check#109 by converting the roster address once in bedAdd:
if len(args) > 0 && !isRemoteImageRef(args[0]) { args[0] = spec.DeployKey(...) } // bed_run.go:197That fix makes the argument a valid deploy key. This failure is the next consequence: charly/check-sidecar-pod is a deploy key, and the deploy's image is check-k8s-deploy-app (charly/charly.yml:1243 — check-sidecar-pod: pod: {image: check-k8s-deploy-app, disposable: true}). A deploy key is not a box name, so handing it to build:generate resolve scopes generation to a box that cannot exist.
RCA
- Mechanism.
prepare-venueresolves what to build from the deploy, and what reachesFilterBoxis the deploy key rather than the deploy'simage:.FilterBox(sdk/deploykit/graph.go:309-312) correctly rejects a name that is not in the box map — the wrong input, not a wrong check. - Missed control. A qualified bed address reaches FilterBox as its NAMESPACE: pod bed deploys fail at prepare-venue with unknown box "openclaw" #28's fix was verified against the string it was reported with (a bare namespace) and closed; nothing asserts the next string in the same chain (the deploy key) is a box name. The arm that would have caught it is "a qualified pod bed with an
image:different from its own name reachesprepare-venue". - Blast radius. Every qualified pod bed whose deploy name differs from its image — including
charly.check-sidecar-pod, which is the reproduction foropencharly/sdk#362and therefore blocks that PR's A2 witness. - Root fix. At the
prepare-venuecall site, resolve the deploy'simage:and pass THAT tobuild:generate resolve; a deploy key must never reach the box namespace. Regression arm: the bed above must reach[deploy-add] PASS.
Note
I have not established whether this is a regression from a later pin or a case #109 never covered — both are consistent with the evidence. Whoever picks this up should start by diffing the prepare-venue → build:generate path since v2026.287.1745.
Agent: containerd-crabbox-program · session 8b1c01cf-7f79-4a75-bff8-240415a06208
Assisted-by: Claude Code DeepSeek V4.1 Flash (analysed on a live system)
Activity
aitrawog commentedon Nov 3, 2026
Trace added — the fallback is three lines, and the real question is why
p.Imageis empty.plugin-deploy-pod/lifecycle.go:So
baseNameisp.Imagewhen the host populated it, and the deploy name otherwise. The failing run asked forcharly/check-sidecar-pod— the deploy KEY — which meansp.Imagearrived empty.That matters because the deploy does declare an image (
charly/charly.yml:1243):Two candidate mechanisms, told apart by one measurement I have not yet made:
Imagefor a qualified deploy (root-scope-only resolution, the same shape asopencharly/charly#819), so the fallback fires; orImagewith the deploy key for a qualified address.Either way the guard is the same shape as the rest of this family: a deploy key must never reach the box namespace. The regression arm remains the bed above reaching
[deploy-add] PASS, and the discriminating measurement is whatp.Imageholds at:318forcharly.check-sidecar-pod— one log line or a debug print on the existing repro, not a new harness.Agent:
containerd-crabbox-program· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code DeepSeek V4.1 Flash (analysed on a live system)
aitrawog commentedon Nov 3, 2026
Third trace — the HOST carries the identical fallback, so
p.Imagebeing empty is the root, not the plugin's guard.charly/charly/build_overlay.go:179:and twenty lines later it normalises the deploy name for the container:
So the host already knows how to split a qualified address — for the CONTAINER name — but its
base(the box to build) falls back to the dotted deploy name whenreq.Imageis empty, exactly asplugin-deploy-pod/lifecycle.go:318does. Two independent fallbacks firing means one upstream fact is missing:req.Imageis empty for this deploy, thoughcharly/charly.yml:1243declaresimage: check-k8s-deploy-app.That points at the deploy-NODE lookup, not at either fallback: a qualified entity resolved through a ROOT-scope map (
rp.Deploy["charly.check-sidecar-pod"]) is absent, so itsimage:is never read — the same shape as opencharly/charly#819, where a qualified bed was invisible to root-scope resolution.The measurement that settles it is one line at
build_overlay.go:179on the existing repro: printreq.Imageandreq.DeployNameforcharly.check-sidecar-pod. IfImageis empty there, the fix belongs in the deploy-node resolution (namespace-aware), not in either fallback — and both fallbacks should then become an ERROR rather than a substitution, so a deploy key can never silently become a box name again.Agent:
containerd-crabbox-program· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code DeepSeek V4.1 Flash (analysed on a live system)
aitrawog commentedon Nov 3, 2026
The link between the two fallbacks, for completeness.
plugin-deploy-pod/lifecycle.go:296:So the chain is one field, passed straight through:
p.Imageis never derived inside the plugin — it is whatever the host prep put there. That is why the fix is upstream of both fallbacks, and why the one-line measurement (req.Imageatbuild_overlay.go:179) is the decisive test: if it is empty there, the host prep is where the deploy's declaredimage: check-k8s-deploy-appis being lost, and the deploy-node lookup for a qualified entity is the place to look — theopencharly/charly#819shape again.I have not located the host prep's construction site; it is not in
charly/charly/host_build_deploy_node*.go,deploy_*.goorbuild_overlay.go, andspechas noPodParams/PrepareVenueRequesttype under those names. Naming that file is the next step.Agent:
containerd-crabbox-program· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code DeepSeek V4.1 Flash (analysed on a live system)
aitrawog commentedon Nov 3, 2026
CLAIM — taking this as
containerd-crabbox-program/46, fixing it inopencharly/plugin-deploy-pod.Scope (plugin-deploy-pod only):
podPrepareVenueandpodRebuildcurrently fall back to the raw deploy KEY whenp.Imageis empty. That key is not a box name. The fix routes both call sites through the plugin's OWN deploy-key→box resolver (resolve_ref.go), which already folds the project's namespace-qualified keys. No resolver semantics change; no second resolver; an explicitp.Imagestill wins untouched.Evidence already on this issue stands:
p.Imagearrives empty because the deploy keycharly/check-sidecar-poddid not resolve to the project's namespace-qualified node (charly.check-sidecar-pod), so the host synthesized a target-only node. The plugin-side resolution is what recoversimage: check-k8s-deploy-app.Planned gate:
go build ./...,go vet ./...,go test ./...incandy/plugin-deploy-pod/, pluscharly box validateat the repo root; a new test drives the extracted resolver helper. The livecharly.check-sidecar-podbed is the regression arm and I will report honestly whether it was run.Agent:
containerd-crabbox-program/46· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)
aitrawog commentedon Nov 3, 2026
STATUS — PR opened: opencharly/plugin-deploy-pod#44 (head
68ed53aca4a1535d0743eaadb27332bbc6f8dffb).Done: both
prepare-venueandrebuildnow resolve the deploy KEY through the plugin's existing deploy-key→box resolver; the two inlinep.Namefallbacks are deleted. Gate on the committed tree:gofmtclean,go build/go vet/go test ./...rc=0,charly box validate0 warnings / 0 errors. The regression test fails on the unmodified tree (and a compiling mutation reproduces the exact pre-fix key).Not proven here: the live
charly.check-sidecar-podbed (the R10 arm) — it needs the umbrella's host-built plugin to carry this change. That limit is stated in the PR body.Next: the org
charly/pr-validatorgate on PR #44. I will fix or rebut every finding in the round, then close this issue after the merge.Agent:
containerd-crabbox-program/46· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)
fix(pod): compose the config ref from the box's registry, not its add…
fix(pod): resolve the deploy key to a box name before prepare-venue/r…
aitrawog commentedon Nov 4, 2026
RESOLVED — a qualified pod bed deploys end to end, and the five defects between the report and the green bed are all closed.
The symptom in this issue —
unknown box "charly/check-sidecar-pod"— was the first of five layers. Each was real, each was fixed in its own repo, and each was only visible once the one before it was gone.unknown box "charly/check-sidecar-pod"plugin-deploy-pod#45(mergede19aa1242b91…, tagv2026.308.1638) —resolveDeployBoxNameForKey, resolved beforeHostBuild("overlay")image not found in local storage: charly.check-k8s-deploy-app:<tag>registry → namespace defaults.registry → box LEAFbefore any existence checkshort-name "charly.check-k8s-deploy-app" did not resolve to an aliascharly#1105(merged43348efbdb8f…, tagv2026.308.1507)FoldMembersnever recursed namespaces, so a deploy-level member's substrate defaulted topodresolving ref "charly.eval-vm" for target "pod"sdk#4831175c7c765…/.351, repaired bysdk#48557221e49b9…/.444andsdk#486ca7aef33e2…/.652;sdk#484closedvmsubstratethe "vm" deploy substrate is not available in this projectcharly#1106(merged0796bdcdb5a5…, tagv2026.308.1359) —plugin-deploy-vmin the import listsdk#484,charly#1083andcharly#1107were filed along the way and are all closed.The proof, on a disposable target, pre-merge. Bed
charly.check-sidecar-pod, run2026.308.1106:RC=0,summary.yml errors: 0, zero stepsok:false, 19 of 19 steps PASS — includingdeploy-add(the overlay builds:Overlay image ready: charly/check-sidecar-pod-overlay:78f78cb77fea),config(the quadlet is written and systemd reloaded),bring-up-members(the VM member deploys — never passed before this chain),check-live, the freshcharly updaterebuild, andcheck-live-rebuild.Two things this issue taught that are worth carrying beyond it:
box validate— I should have checked the cheap instrument before the expensive one.box validatecaught it. That is the argument for always running the consumer's gate, not just the producer's tests.Agent:
containerd-crabbox-program· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code ollama-cloud/deepseek-v4.1-flash (fully tested and validated)