mando-cli v0.4.0 — mando up fails on missing target/release/mando_bess (2026-06-25)

The next failure after the 2026-05-26 compose-runtime triage fixes (commit 2233959): once the context: and mocked-slug bugs were resolved, mando up on a fresh clone with the default profile now aborts inside docker compose build because the mando runconfig is build, but mando/Dockerfile is a thin runtime image that COPYs a pre-compiled target/release/mando_bess — and nothing in the up flow ever compiles it.

For Agents

This is a design gap, not a runtime bug: the default profile mando-mocked-algos maps mando → the build runconfig, and the build runconfig + mando/Dockerfile assume cargo build --release already ran (a CI-only invariant). On any fresh checkout the COPY layer has no binary and the whole stack build aborts. Workaround today: mando up --mando=pull (pulls the released registry image instead of building). Durable fix is a 2-part decision pending user sign-off (flip default to pull + add a preflight guard) — NOT yet implemented.

Status

Diagnosed, fix pending user decision. No code change committed. The v0.4.0 binary distributed via install.ps1 cannot run the default mando up on a clean checkout without the workaround.

Reporter

  • gabi (gabriel.vasile1), remote QA tester, on WSL, mando-cli v0.4.0, date 2026-06-25.
  • Running default mando up (profile mando-mocked-algos) on a fresh clone.

Symptom

mando up issues docker compose up -d --build and the build aborts at the mando image’s final COPY:

#14 [mando 6/6] COPY target/release/mando_bess /usr/local/bin/mando_bess
ERROR: failed to compute cache key: "/target/release/mando_bess": not found

Collateral: the bess-trader-dashboard build shows CANCELED (buildkit aborts sibling builds once one target fails), so the failure can read as a dashboard problem — it is not.

Root cause (verified by reading source)

The mando service’s runconfig under the default profile is build, which emits a real build: section pointing at mando/Dockerfile. But that Dockerfile is a thin runtime image that copies a pre-built binary — it does not compile from source — and no step in the up flow runs cargo build --release. So on a fresh checkout the binary the COPY expects does not exist.

1. mando/Dockerfile is a thin runtime image

FROM debian:13.1-slim AS runner
# ... line 17:
COPY target/release/mando_bess /usr/local/bin/mando_bess
# ...
CMD ["mando_bess"]

It copies a pre-compiled binary. There is no Rust build stage — building this image presupposes target/release/mando_bess already exists on the build context.

2. mando/bess-service.yaml:23-32 encodes the CI assumption

build:
  mode: dockerfile
  context_includes:
    - mando-bess/certs
    - lib/libduckdb/.../libduckdb.so
    - target/release/mando_bess        # <-- assumes cargo build --release already ran

The context_includes list (the yaml-driven build-context filter from mando-cli-build-context-filter-2026-05-06) explicitly ships the pre-built binary into the build context. This only holds in CI, where cargo build --release precedes the image build.

3. The default profile maps mandobuild (and so do the other builtins)

src/runtime/runprofile.rs:

Profilemando runconfigline
mando-mocked-algos (default)buildrunprofile.rs:225
mando-fullbuildrunprofile.rs:237
mando-fast-devbuild-devrunprofile.rs:249

No builtin profile maps mando to pull or artifact. Every default path goes through a runconfig that wants the binary.

4. The build runconfig emits a real build: (nothing compiles mando_bess)

src/runtime/templates/runconfig/build.yml:10-12 renders a real build: block. The host-side compile flag --cargo that would produce the binary is gated to the artifact runconfig only (src/cli.rs:55) — it is not part of the build/up path. So the up flow:

  1. picks build for mando (step 3),
  2. renders a build: section (step 4),
  3. never runs cargo build --release,
  4. → COPY of a non-existent binary → abort.

Net

Any tester on a fresh clone running the default mando up hits this. It works in CI only because CI pre-builds target/release/mando_bess before the compose build. This is the same class of “ships-as-the-default-but-never-exercised-against-a-fresh-checkout” gap called out in the 2026-05-26 process lesson.

Immediate workaround (no code change)

Unblock gabi now

mando up --mando=pull

The per-service override syntax --<service>=<runconfig> is documented at src/cli.rs:78. The pull runconfig (src/runtime/templates/runconfig/pull.yml) swaps the build: section for image: ${MANDO_IMAGE:-…} and adds a docker compose pull, so it fetches the released image instead of compiling.

On gabi’s box the image ref resolves to:

registry.gitlab.com/alpiq_cicd/sales-and-origination/flexible-assets/bess/poc/mando:1.10.0-2533146896.b06b6b59

and he is authenticated to that registry, so the pull succeeds and the stack comes up with the released mando image. (This ref is not hardcoded in mando-cli source — it comes from workspace config / env; see Risk under the durable fix.)

Durable fix (decision pending — NOT implemented)

Two parts; both require user sign-off before implementing.

Part 1 — flip the default profile’s mando runconfig buildpull

Change runprofile.rs:225 so mando-mocked-algos resolves mando to pull instead of build. A fresh clone would then pull the released image by default and never hit the COPY.

Open risk — confirm the clean-checkout default image ref

The pull runconfig’s image comes from ${MANDO_IMAGE:-…}. The registry ref is NOT hardcoded in mando-cli source — it is supplied by workspace config / env. Before flipping the default, confirm a clean checkout’s default MANDO_IMAGE points at the GitLab registry (e.g. the registry.gitlab.com/.../mando:<tag> above), not a local tag like mando:dev. If the default resolves to a local-only tag, the pull 404s for anyone who hasn’t built locally — trading one fresh-clone failure for another.

Part 2 — add a preflight guard in up

If the resolved mando runconfig is build (or build-dev) and target/release/mando_bess is missing, fail early with an actionable message (e.g. “mando_bess not built — run cargo build --release or use mando up --mando=pull”) instead of letting buildkit fail deep in the COPY layer with a cryptic cache-key error.

This guard is valuable independent of Part 1: anyone who deliberately selects the build runconfig (local source iteration) still benefits from the early, actionable failure.

#ActionFile(s)Gate
1Confirm clean-checkout default MANDO_IMAGE → GitLab registry ref (not mando:dev)workspace config / env (not mando-cli source)blocks Part 1
2Flip default profile mando runconfig buildpullsrc/runtime/runprofile.rs:225user decision
3Add preflight guard: build/build-dev runconfig + missing target/release/mando_bess → early actionable errorsrc/commands/up.rs (resolve site)user decision
4Communicate workaround mando up --mando=pull to gabinow
  • mando-cli-v0.4.0-piped-output-invisible-failures-2026-06-25follow-up found while validating the --mando=pull workaround above. When up output is piped/redirected (the tester does 2>&1 | tee log), failures were INVISIBLE: docker compose writes progress+errors to /dev/tty (fix: --progress plain) and indicatif::MultiProgress::println is a non-TTY no-op (fix: eprintln! fallback on !stderr().is_terminal()). With both fixed, the workaround’s own wall became visible: a registry pull access denied (needs docker login, distinct from mando-cli’s GitLab-API auth).
  • mando-cli-v0.4.0-compose-bugs-triage-2026-05-26 — the previous failure on this exact path; its fixes landed in commit 2233959, and clearing them surfaced this binary-missing gap as the next blocker. Documents the load-bearing profiles: ["{run_tag}"] invariant and the default-mocked-profile-vs-fresh-checkout coverage hole.
  • mando-cli-v2 — current architecture (AppContext, CommandDelegate, runtime pipeline) that the profile/runconfig resolution lives in.
  • mando-cli-build-context-filter-2026-05-06 — the yaml-driven context_includes mechanism (bess-service.yaml) that ships the pre-built binary into the build context — the CI assumption made explicit.
  • mando-cli-wsl-linux-build — the install.sh / install.ps1 distribution channel that delivered the v0.4.0 binary gabi is running on WSL.
  • mando-cli-build-variants-shelved-2026-05-06 — shelved profile-driven build-variant design (dev vs release Dockerfile, pre_command) that, had it shipped, would have covered the “compile-then-image” path the default profile silently assumes.
  • Spec: /Volumes/bandi/coding/poc/mando-cli/docs/superpowers/specs/2026-05-13-compose-runtime-design.md
  • Plan: /Volumes/bandi/coding/poc/mando-cli/docs/superpowers/plans/2026-05-13-compose-runtime.md