Skip to content

feat(demo): close the OTA loop for the rep demo - #16

Closed
mrangelmarino wants to merge 1 commit into
mainfrom
feature/yolo-demo
Closed

feat(demo): close the OTA loop for the rep demo#16
mrangelmarino wants to merge 1 commit into
mainfrom
feature/yolo-demo

Conversation

@mrangelmarino

Copy link
Copy Markdown
Collaborator

Summary

Three-change branch that takes the closed-loop demo from "agent receives MQTT cmd then dies" to "operator triggers rollout, robot's path in Gazebo changes live within 6 seconds." Verified end-to-end on Apple Silicon: drive-circle auto-starts, `make demo-swap` triggers `PHASE_PULLED → PHASE_SWAPPED → PHASE_HEALTHY`, robot-app container swaps to figure-eight-v1, rover path changes in noVNC.

Three changes

  1. Install `docker-ce-cli` in the agent container. Bookworm's stock `docker.io` ships CLI API 1.41; Docker Desktop's daemon is on 1.44+. The mismatch caused every OTA `docker pull` to fail before `PHASE_PULLED` was acked. We pull `docker-ce-cli` from Docker's official apt repo at agent startup so the API matches the daemon. (Yak feat(sim): serve Gazebo GUI via noVNC (browser GUI on :14680) #4 closed: agent now has Docker 29.4.2.)

  2. Auto-start a `robot-app` service running `circle-v1`. New compose service with `container_name: robot-app` so the agent's OTA Swap (`docker rm -f robot-app + docker rename robot-app-new robot-app`) replaces it cleanly on the first rollout. Network: `default` (= `temporal-hack-lab_default`, same network OTA-spawned containers land on via `OTA_RUN_ARGS`). `depends_on` sim started + mqtt healthy so we don't publish Twists into the void during startup.

  3. `make demo-swap` target. One-line OTA rollout fire to `localhost:14050/robot-app:figure-eight-v1`. Matches the existing `sim-drive-*` convention (inline `## ` help comment, no `container-check` dep since this is just curl to the host).

Also wires `DOCKER_DEFAULT_PLATFORM=linux/amd64` on the agent because controller images are built `--platform=linux/amd64` (their Humble base is amd64-only), and on Apple Silicon the daemon defaults to arm64 and refuses the amd64-only manifest.

Why this matters for the demo

The closed-loop story is "operator triggers OTA → Temporal phases progress → robot's path in Gazebo changes live." Telemetry alone is data on a dashboard; behavior swap is the orchestration doing something the rep can see with their eyes. With this branch, the rep's path becomes:

```bash
make sim-up # rover spawns, starts circling
open "http://localhost:14680/vnc.html?autoconnect=1&resize=scale"
make demo-swap # ← THE moment

rover's path changes from circle to figure-8 in ~6 seconds;

Temporal UI at :14080 shows phases progressing in parallel

```

(Note: the host-side `./bin/controlplane` and `./bin/ota-worker` still need to be started separately — they're not in compose yet. See "Future work" below.)

Test plan

  • `make sim-down && docker rmi temporal-hack/sim:dev && make sim-up` brings up sim + agent + robot-app cleanly on a cold cache (~2-3 min).
  • `docker exec temporal-hack-lab-agent-1 docker --version` returns 29.4.x (was 20.10 / docker.io previously).
  • `robot-app` container running `circle-v1` immediately after `make sim-up`; rover visibly driving in a circle in the noVNC browser.
  • `make demo-swap` returns `{"rollout_id":"..."}` and within ~6 seconds:
    • `docker inspect robot-app --format '{{.Config.Image}}'` shows `figure-eight-v1`
    • rover's path changes to figure-8 in the browser
    • Temporal UI at :14080 shows the workflow stepping through phases
  • Reverse swap (figure-8 → circle) also works via `curl POST /v1/ota/rollouts` with `circle-v1` image_ref. Verified bidirectional.
  • Pre-push hook green: cloud + agent vet/test, ruff, ci-cluster smoke. (Changes don't affect ci-cluster smoke since `docker-compose.sim.yml` isn't part of CI.)

Out of scope / future work

  • Auto-start `./bin/controlplane` and `./bin/ota-worker` as part of `make sim-up` (or a new `make demo-up`). Currently a manual step; easy to forget. Worth a small follow-up.
  • Cleanup of OTA-replaced robot-app container on `make sim-down`. After a swap, the OTA-managed `robot-app` is left dangling because compose doesn't know about it; cycling sim-up/down requires `docker rm -f robot-app` between. Either add it to `sim-down` or document.
  • Multi-arch controller images. `DOCKER_DEFAULT_PLATFORM=linux/amd64` is a workaround. Building controller images as multi-arch (amd64+arm64) would let Apple Silicon run native and remove the env hack. Low priority; emulation is fast enough.
  • Explicitly NOT merging PR chore(mqtt): use developer's cloudflared tunnel on :7883 #13 (cloudflared broker tunnel). The demo runs locally; an external tunnel adds risk for no demo benefit.

Architecture

See the [mermaid diagram in the conversation transcript] — three trust boundaries (host / lab compose project / sim container internals), two viewing surfaces (Temporal UI + noVNC), two parallel planes (OTA control via host binaries→Temporal→MQTT→agent→docker, runtime data via robot-app→ROS 2→bridge→Ignition→rover joints).

🤖 Generated with Claude Code

Three-change YOLO branch that takes the closed-loop demo from "agent
receives MQTT cmd then dies" to "operator triggers rollout, robot's
path in Gazebo changes live within 6 seconds." Verified end-to-end on
Apple Silicon: drive-circle auto-starts, `make demo-swap` triggers
PHASE_PULLED → PHASE_SWAPPED → PHASE_HEALTHY, robot-app container
swaps to figure-eight-v1, rover path changes in noVNC.

1. **Install docker-ce-cli in the agent container.** Bookworm's stock
   `docker.io` ships CLI API 1.41; Docker Desktop's daemon is on 1.44+.
   The mismatch caused every OTA `docker pull` to fail before
   PHASE_PULLED was acked. We pull docker-ce-cli from Docker's
   official apt repo at agent startup so the API matches the daemon.

2. **Auto-start a robot-app service running circle-v1.** New compose
   service with `container_name: robot-app` so the agent's OTA Swap
   (`docker rm -f robot-app + docker rename robot-app-new robot-app`)
   replaces it cleanly on the first rollout. Network: `default` (alias
   for `temporal-hack-lab_default`, same network OTA-spawned containers
   land on via OTA_RUN_ARGS). Depends on sim started + mqtt healthy so
   we don't publish Twists into the void during startup.

3. **`make demo-swap` target.** One-line OTA rollout fire to
   localhost:14050/robot-app:figure-eight-v1. Matches the existing
   sim-drive-* convention (inline `## ` help comment, no
   container-check dep since this is just curl to the host).

Also wires `DOCKER_DEFAULT_PLATFORM=linux/amd64` on the agent because
controller images are built --platform=linux/amd64 (their Humble base
is amd64-only), and on Apple Silicon the daemon defaults to arm64 and
refuses the amd64-only manifest.

What this does NOT do (out of scope for the YOLO demo):
- Doesn't clean up an OTA-replaced robot-app container on `make
  sim-down`. After a swap, the OTA-managed container is left dangling;
  cycling sim-up/down requires `docker rm -f robot-app` between.
- Doesn't merge the partner-track PR #13 (cloudflared broker tunnel).
  The demo runs locally; an external tunnel only adds risk.

Demo path:
  make sim-down && docker rmi temporal-hack/sim:dev && make sim-up
  open http://localhost:14680/vnc.html?autoconnect=1&resize=scale
  # rover starts driving in a circle automatically
  make demo-swap
  # rover's path changes to figure-eight; Temporal UI at :14080 shows phases

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mrangelmarino

Copy link
Copy Markdown
Collaborator Author

Superseded by parallel work from @bkearns: feat(agent): docker/podman engine auto-detect + native macOS run mode (commit ba20592) solves the agent's Docker CLI issue by running the agent natively on the host, and feat(make): controlplane-up + ota-circle / ota-figure-eight targets (3e846e0) replaces both make demo-swap and the auto-start compose service with a more granular OTA build-push-roll loop. The remaining piece — auto-starting an initial robot-app — is now done explicitly via make ota-circle rather than a compose service. PR #14's sim split into gazebo + robot services also conflicts with my compose-service approach. Closing as obsolete; the demo now runs from main.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant