mando-cli Simulator Runtime
Second first-class Docker Compose stack (mando-sim) added to mando-cli-v2 for running the BESS simulator alongside the dev stack. Coexists with the dev mando project — neither evicts the other. Landed on feature/simulator-runtime at commit b244f2e.
For Agents
Authoritative in-repo design + plan (do not transcribe — read directly):
- Spec:
/Volumes/bandi/coding/poc/mando-cli/docs/superpowers/specs/2026-05-28-simulator-runtime-design.md- Plan:
/Volumes/bandi/coding/poc/mando-cli/docs/superpowers/plans/2026-05-28-simulator-runtime.mdRead those when implementing the orchestrator/runner services or extending CLI behavior. This note captures the durable knowledge that does not belong in the spec: status, decision rationale, audit findings, and process lessons.
Status (2026-05-30)
Services are WIP — CLI leads the contract
The CLI was built ahead of the simulator services. The runtime contract here (env names, ports, image references) is what services MUST implement.
- mando-cli simulator runtime: landed on
feature/simulator-runtime(commitb244f2e), pushed to origin. MR creation link:https://gitlab.com/alpiq_cicd/sales-and-origination/flexible-assets/bess/poc/mando-cli/-/merge_requests/new?merge_request[source_branch]=feature/simulator-runtime - mando-cli validation: unit-test validated. Full
cargo test: 785 passed, 1 ignored (the docker-requiringtests/up_compose_smoke.rs). Clippy unchanged frommainbaseline (pre-existing dead-code only). - 27 files changed, +1280 / −240, +2 new files:
src/runtime/service_stack.rs— sharedselect_profiletwo-stack resolversrc/runtime/templates/simulator/simulator.yml
- Authored solely by
andras.lederer(no co-author trailer).
These do not exist yet
The following will be authored against the contract defined here:
mando_simulatorcrate +Dockerfile.simulatorin thebess/poc/mandorepo (orchestrator image)simulator-runnerimage atbess/simulator/runner(base for the six runners)- Six sim repos:
forecast,optimization,execution,market,asset,post-delivery-marketTrue end-to-end
mando up -p simulatoris deferred until those images land. Today: unit-test green only.
The Redesign Decision
Supersedes GitLab MR !2 /
feature/BE-2256(balint)andras took over and redesigned. The shape below is materially different from MR !2.
Key choices vs MR !2:
| # | Choice | Rationale |
|---|---|---|
| 1 | Simulator runs as its OWN Compose project mando-sim (not the dev -p mando project) | Two stacks coexist; neither tears the other down. Stack isolation is a first-class concept. |
| 2 | Six runners generated from a single data-driven Rust list (SIMULATOR_RUNNERS) | Single source of truth. MR !2’s hardcoded/commented YAML was un-DRY and error-prone. |
| 3 | Own Postgres (sim-postgres, host port 5433, DB bess_simulation) | Isolated from dev DB. Avoids 5432 collision and accidental cross-talk. |
| 4 | Dropped the host_project() concept entirely | mando-simulator is a service, not a Project variant. Only Project::SimulatorRunner is added as a real cloned repo. |
| 5 | New Project::DEV subset that excludes SimulatorRunner | Lets dev iterations skip the simulator clone path entirely. |
| 6 | RunProfile gains compose_project + derived layers(); commands route off profile.compose_project(); compose::assemble matches layers() to pick the compose-file set | Routing decision is centralized on the profile, not scattered in command code. |
| 7 | Env reaches compose by extending fill_build_args to merge the full workspace .env (NOT via --env-file) | --env-file would hard-fail when .env is missing. fill_build_args is tolerant and already plumbed. |
| 8 | Python healthcheck (not curl); Gurobi license is a file mount, not multiline env | Runner image already has Python; avoids curl install. Multiline env vars cross compose/shell layers badly. |
| 9 | Two-stack ergonomics: status shows both stacks; logs/exec/volume auto-resolve stack from service name via shared service_stack::select_profile; down -p simulator -v has a confirmation guard | One resolver, no duplicated flows. Volume wipe needs human confirmation. |
§A Orchestrator ↔ Runner Env Contract
SUPERSEDED 2026-06-02 — see mando-cli-simulator-env-contract-2026-06-02
The contract below was CLI-led and predated the real orchestrator/runner images. On 2026-06-02 (commit
c3f0af7) it was realigned to matchsimulator:1.11.0-feat.2569583284.7d69a070+ runner shapef7aa42f. Major changes:POSTGRES_*→SIMULATOR_DATABASE_*;SIMULATOR_RUNNERSCSV → per-runnerSIMULATOR_<NAME>_HOST; repo URL/branch/commit_hash moved from orchestrator to runners; schemabess_simulation→simulator; healthcheck Python → curl;GRB_LICENSE_FILEfile mount →GUROBI_LICenv var. Use the follow-up note as the authoritative contract.
CLI-defined — services implement to this
This is the load-bearing API surface. Changing env names or default ports breaks the simulator runtime contract.
Runner env (per simulator-<name> container)
| Variable | Value / Default |
|---|---|
SERVER_PORT | per-runner port (see runner list) |
APP_NAME | simulator-<name> |
SIMULATION_MANDO_HOST | mando-simulator |
SIMULATION_MANDO_PORT | 8080 (internal) |
GITLAB_TOKEN | from workspace env |
NEXUS_INDEX_URL | from workspace env |
GRB_LICENSE_FILE | optimization runner only; mounted from ${GUROBI_LIC_FILE:-./gurobi.lic} |
Runner contract: must expose GET /health.
Orchestrator env (mando-simulator)
| Variable | Purpose |
|---|---|
SIMULATOR_<NAME>_REPO_URL | per-runner repo URL |
SIMULATOR_<NAME>_BRANCH | per-runner branch (defaults to main) |
SIMULATOR_<NAME>_COMMIT_HASH | per-runner pinned commit |
SIMULATOR_RUNNERS | comma-separated endpoint list simulator-<name>:<port> pairs |
POSTGRES_HOST | sim-postgres |
POSTGRES_PORT | 5432 (internal — host port is 5433) |
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB | from workspace env |
SIMULATOR_DB_SCHEMA | simulator schema name |
Audit + Fixes
A multi-perspective audit after the initial implementation found the following; all closed before final commit.
HIGH severity
mando statusshowed spuriousmando-simfailure row —run_capturehad no empty-files guard. With no simulator compose files present, the call returned a synthesized “failure” row. Fix: guardrun_captureagainst empty file sets.
Functional bugs
volume clear sim-postgrescouldn’t find the container —volume clearwas assembling dev compose files and not finding the simulator service. Fix: route through the sameservice_stack::select_profileflow aslogs/exec. Single resolver, no duplication.mando get simulator-runner404’d —getdidn’t resolve aliases, so the back-fill hint pointed to a non-existent target. Fix: makegetalias-aware.pull/ status alarmed on the un-cloned runner — Loud red rows for what is intentionally a not-yet-cloned repo. Fix:pull/collector show calm “not cloned” rows.
DRY violations (six single-source-of-truth misses)
- No shared
SIMULATOR_PROJECT_NAMEconst → string-literal duplication. Fix: added shared const. - No shared
SIMULATOR_PROFILE_NAMEconst. Fix: added shared const. - No shared sim-service-name const. Fix: added shared const.
- Redundant
SimRunner.repofield (derivable). Fix: removed. volume clearhad its own resolution path duplicatinglogs/exec. Fix: all three use sharedservice_stack::select_profile.
A final fresh-eyes re-review confirmed all closed; no new comments / no new anyhow / no new duplicated flows introduced.
Process Lesson
Verify with full
cargo test, NOTcargo test --bin mandoDuring per-task verification we used
cargo test --bin mando. This skips integration tests intests/— which masked a compile break intests/up_compose_smoke.rswhereRunProfileliterals lacked the newcompose_projectfield. The final review caught it.Rule going forward: verify with plain
cargo test(orcargo test --workspaceif multi-crate). Never--bin mandofor green-light validation — it lies by omission.
File-level Touchpoints
-
New:
src/runtime/service_stack.rs—select_profile(service_name)two-stack resolver -
New:
src/runtime/templates/simulator/simulator.yml -
Modified core:
src/runtime/runprofile.rs(addedcompose_project,layers()),src/runtime/templates.rs, runconfig artifact/build/build_dev yaml files, andsrc/commands/up.rs -
Modified commands:
status,logs,exec,volume,down,get,pullfor two-stack awareness -
Modified workspace:
Projectenum gainsSimulatorRunner; newProject::DEVsubset
Related
- mando-cli-simulator-env-contract-2026-06-02 — follow-up: §A env contract realigned to real images + arbitrary-extras passthrough
- mando-cli-v2 — overall architecture this slots into
- mando-cli-docker-lifecycle — Docker primitives this builds on
- mando-cli-v0.4.0-compose-bugs-triage-2026-05-26 — preceding compose-runtime fixes (v0.4.0 baseline)
- Mando — the service the orchestrator wraps
- Alpiq BESS — project overview