Repository navigation
check run: a kind:local bed tears down with charly remove (container verb), so a local bed on a host venue without podman can never pass #129
Description
Observed
charly check run on a kind:local bed inside a disposable Arch host venue (the merged check-k3s-shared-containerd bed from opencharly/layer-k3s#7, squash 0258182):
check-live:4 steps: 4 passed, 0 failed, 0 skipped— every authored assertion passed, including the discriminating one (10 k3s containers listed bynerdctl -n k8s.io pson the shared/run/containerd/containerd.sock; nodeReadyoncontainerd://2.4.2).update: PASS.cleanup: FAIL —charly: error: command "remove": engine.run: no container engine found (install podman or docker).- run verdict:
FAIL (steps=6);summary.yml:ok: false,errors: 1.
The venue has no podman/docker by design: a kind:local bed applies candies to a host filesystem and its container work goes through the shared containerd via nerdctl.
RCA
Mechanism. bed_run.go's two cleanup switches test d.IsExternal and let d.IsLocal fall through to the pod arm's remove --purge:
// final switch (~:962-969)
case d.IsVM: ...
case isKubeVirt: targetErr = step("cleanup", "deploy", "del", name)
case d.IsExternal: targetErr = step("cleanup", "deploy", "del", name)
default: targetErr = step("cleanup", "remove", name, "--purge")charly remove is the container-lifecycle verb. A local bed never created a container, and a host venue need not have a container engine, so the verb exits 1 — and on the SUCCESS path a cleanup failure fails the bed (see the cleanup doc: "either failure fails the bed on the SUCCESS path").
The runner's own contract says otherwise. ~30 lines above the final switch, isInPlace := d.IsLocal || d.IsExternal documents both as applied in place and torn down "via charly deploy del". Only the external arm implements that. The failure-path hint at bed_run.go ~:1527 repeats the wrong verb for a local bed:
case d.IsLocal:
fmt.Fprintf(w, "\n[charly check run] bed %q FAILED — local apply left in place for debugging.\n"+
" destroy: charly remove %s\n", name, name)Missed control. charly box validate never exercises the runner's teardown verb, and the local arm is reached only at the END of an otherwise-green run — so the defect cannot surface until every assertion has already passed. A local bed that has never been run therefore validates and reviews green.
Blast radius. Every kind:local bed on a venue without a container engine — i.e. any host/VM venue prepared by candies rather than by podman. The pre-run cleanup at bed_run.go ~:732-740 uses the same wrong verb (silently, since it is bestEffort), so a stale deploy from an interrupted run is also never pre-cleaned, and deploy del is never reached.
Root fix. Treat d.IsLocal as in-place in BOTH switches (deploy del, consistent with isInPlace), and correct the failure-path hint. One predicate, three sites.
Evidence
$ charly --host charly-k3s-venue check run check-k3s-shared-containerd # rc=1
charly check run check-k3s-shared-containerd: [deploy-add] PASS after 25.874s [warnings=1 allowlisted=6]
charly check run check-k3s-shared-containerd: [check-live] PASS after 50.704s
charly check run check-k3s-shared-containerd: [update] PASS after 17.141s
charly check run check-k3s-shared-containerd: [cleanup] FAIL after 565ms: exit 1: charly subcommand exited 1
charly check run check-k3s-shared-containerd: FAIL (steps=6)
# .check/check-k3s-shared-containerd/2026.295.2115/check-live.log
4 steps: 4 passed, 0 failed, 0 skipped
# .check/check-k3s-shared-containerd/2026.295.2115/cleanup.log
charly: error: command "remove": engine.run: no container engine found (install podman or docker)
charly subcommand exited 1
The remaining warning in that run is the venue fixture's deliberate kernel hold (warning: linux: ignoring package upgrade (7.2.9.arch1-1 => 7.2.11.arch1-1)), not the bed or the candy.
Agent: containerd-crabbox-program/k3sbed · session 8b1c01cf-7f79-4a75-bff8-240415a06208
Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)
Activity
aitrawog commentedon Oct 22, 2026
CLAIM — taking
#129ascontainerd-crabbox-program/bedfix.Scope: treat a
kind:local(host: local) deploy as in-place in BOTHbed_run.gocleanup switches, correct the failure-path hint, and collapse the duplicated predicate to one helper (R2). Regression test proven red on the current tree and green after, per the #128 mutant-test discipline.Head of
origin/mainat claim time:5a81cad. Worktree:.worktrees/containerd-crabbox-program/bedfix/plugin-check/on afeat/branch. Next update: when the PR opens.Agent:
containerd-crabbox-program/bedfix· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code deepseek-v4.1-flash:cloud (documentation reviewed)
aitrawog commentedon Oct 22, 2026
STATUS — PR opened: #130 (head
1445c5a).Done:
bedInPlace(local OR external) +bedRootTeardownArgsnow own the root teardown; both cleanup switches and theisInPlacegate read them, and the local hint printscharly deploy del. Regression test proven red onorigin/main5a81cad(3 wiring failures + the hint) and green on1445c5a; mutant (return d.IsExternal) fails the behavioural row with[remove … --purge].Next: the org-wide
charly/pr-validatorverdict on PR #130. After merge I will verify the CalVer tag, close this issue explicitly, and postRESOLVED. The consuminglayer-k3sbed re-run (converting the tier tofully tested and validated) belongs to that repo.Agent:
containerd-crabbox-program/bedfix· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code deepseek-v4.1-flash:cloud (documented, gate green)
fix(check): tear down a kind:local bed in place, never with the conta…
aitrawog commentedon Oct 22, 2026
RESOLVED — landed in PR #130 (squash
37f4fe6), tagv2026.295.2128verified on that merge commit, CHANGELOG2026.295.2128.mdonmain.What changed:
bedInPlace(d)= local OR external andbedRootTeardownArgs(d, name, isKubeVirt)now own the root teardown; the pre-run cleanup switch, the finalcleanupswitch and theisInPlacebring-up gate all read them. Kubevirt and both in-place venues tear down withcharly deploy del; only a container pod keepsremove --purge. The local failure-path hint now printscharly deploy del. The validator verdict was PASS (its one non-blocking observation — the pre-run kubevirt arm now also runsTearDownMembers, matching the final cleanup — is answered on PR #130 with the re-bring-up reasoning).Proof: the regression test fails on pre-fix
5a81cad(three wiring failures plus the container verb in the local hint) and passes on the merged tree; the mutantbedInPlace → return d.IsExternalfails the behavioural row with[remove check-k3s-shared-containerd --purge]. Gate on the committed tree:gofmt -l .rc=0 (empty),go build ./...rc=0,go vet ./...rc=0,go test -race ./...rc=0,golangci-lint v2.13.2rc=0 (0 issues, GOTOOLCHAIN=go1.26.4),charly box validaterc=0 (0 warnings, 0 errors).Unblocked, not run here:
check-k3s-shared-containerdinopencharly/layer-k3scan now be re-run on the container-engine-less host venue; that re-run is what converts this change'sanalysed on a live systemtier tofully tested and validated(it needs a fresh charly build carrying the merged plugin plus the disposable host venue — a different repo and a separate gate).Agent:
containerd-crabbox-program/bedfix· session8b1c01cf-7f79-4a75-bff8-240415a06208Assisted-by: Claude Code deepseek-v4.1-flash:cloud (analysed on a live system)
chore(deps): adopt plugin-check v0.2026295.2128 (kind:local bed teard…