> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cyberwave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Product updates and announcements

<Update label="May 25, 2026">
  ## Platform

  * **Audio recording is now decoupled from the live audio stream**: The microphone driver's `start_audio` / `stop_audio` commands on `cyberwave/twin/{uuid}/command` now drive **only** the WebRTC audio producer — no file is written as a side effect. The driver replies on `…/start_audio/status` (and `…/stop_audio/status`) with `{ "type": "audio_started" | "audio_stopped", "status": "ok" | "error", "source_type": "edge", "timestamp": … }`. This is symmetric with the camera driver's `start_video` / `stop_video` contract.
  * **Recording rides on `webrtc-command`**: Persisted audio recording is now controlled by `start_recording` / `stop_recording` published on `cyberwave/twin/{uuid}/webrtc-command` — the same topic and payload shape the Recorder workflow node already uses for video. The media-service SFU replies on `…/webrtc-command/status` with the authoritative `recording_id`. The frontend audio widget's REC button publishes there directly (no detour through the driver). The microphone driver also accepts `start_recording` / `stop_recording` on the command topic as a **fallback relay** for callers that don't speak `webrtc-command`; on that path the driver forwards verbatim to `webrtc-command` and lets media-service own the ACK.
  * **Audio widget has two independent controls**: The right-panel audio widget now exposes a **mic on/off** toggle (drives the live stream) next to the **REC** button (drives recording). Both flip to their "on" state only after the matching ACK arrives, so the indicators never lie about the underlying state.
  * **`auto_recording_audio` and `enable_recording` semantics preserved and tightened**: `CYBERWAVE_METADATA_AUTO_RECORDING_AUDIO=true` still sets `recording: true` on the **initial** WebRTC offer so recording auto-starts at startup; after that, recording is driven entirely by `start_recording` / `stop_recording`. `CYBERWAVE_METADATA_ENABLE_RECORDING=false` now silently drops only the driver's fallback relay — `start_audio` is unaffected, and frontend/Recorder publishes straight to `webrtc-command` (no longer gated by the driver flag).

  ## Docs

  * [Native Microphone Driver](/feature-reference/edge/drivers/native-microphone-driver) and the [generic-microphone driver README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-runtime/runtime-services/drivers/native/cyberwave/generic-microphone) document the two contracts and the fallback relay with concrete payloads.
  * [Recorder node](/feature-reference/workflows/recorder) cross-references the audio widget so it's clear all three callers (FE REC, Recorder node, driver fallback) converge on the same media-service handler and the same `webrtc-command/status` ACK.
</Update>

<Update label="May 20, 2026">
  ## Platform

  * **Real-time alerts when the DJI driver refuses a command**: The Cyberwave Edge for DJI Android driver now raises a Cyberwave alert (`POST /api/v1/alerts`) every time it rejects a command before reaching the aircraft — missing `metadata.drivers.default.virtual_stick` opt-in, location permissions not granted, parked on a landing/RTH confirmation prompt. Each alert carries the `command`, an `error_code` (`VIRTUAL_STICK_OPT_IN_MISSING`, `PENDING_LANDING_CONFIRMATION`, …) and a remediation hint in the description, so the operator sees *why* a key press did nothing in the alerts panel instead of having to pull `adb logcat`. The existing `driver_action_failed` critical-alert path for SDK-level failures (takeoff / land / gimbal) is unchanged.
  * **No-motion watchdog for silently-capped commands**: The Virtual Stick send loop now compares the commanded body-frame linear velocity magnitude against `KeyAircraftVelocity` (NED) every tick, and fires a `driver_aircraft_not_moving` warning alert when the aircraft is reporting `isFlying = true` but observed velocity stays below 0.15 m/s for ≥ 2 s while the operator is commanding ≥ 0.4 m/s. The alert metadata carries the current `flight_mode`, GPS sat count + signal level, commanded vs observed velocity magnitudes, and the raw body-frame target — covering the cases where the MSDK's fire-and-forget `sendVirtualStickAdvancedParam` silently swallows commands (almost always indoor → no GPS lock, restricted-zone proximity, IMU heating, or low-battery saver). Rate-limited to one alert per stuck episode.
  * **Primary suspect surfaced in the alert name**: The `driver_aircraft_not_moving` alert ranks the most likely cause from telemetry and folds it into the alert *name*, so the operator sees the root cause in the alerts list without expanding the description. `Aircraft not moving (GPS-denied: 0 satellites)` is the indoor-flight case (the Mini 4 Pro requires GPS lock for sustained translational motion under Position mode; vertical still works because the barometer gives the FC an absolute altitude reference). `Aircraft not moving (FC in ATTI mode)` is the compass-interference / forced-ATTI case. `Aircraft not moving (cause unknown)` falls back to restricted-zone / IMU heating / battery saver / wind. The full description lead-paragraph repeats the suspect in human-friendly language with the matching remediation hint.
  * **No more spurious "RC reclaimed" log on every Virtual Stick arm**: MSDK pushes a `currentFlightControlAuthorityOwner = null` (mapped to `UNKNOWN` at our boundary) in the very first state update right after `enableVirtualStick.onSuccess`, before the FC has acknowledged authority transfer. The driver used to treat any non-MSDK authority — including `UNKNOWN` — as an RC reclaim and stopped the send loop, only for the next operator axis update to re-arm milliseconds later. The fix: only explicit `RC` / `OSDK` owners are genuine reclaims; `UNKNOWN` is "no signal yet".
  * **MQTT subscriber survives driver-side throws**: The driver's MQTT command dispatch is now wrapped in a top-level catch that fires a `driver_dispatch_exception` critical alert (with a truncated stack trace in the alert metadata) instead of letting an unchecked throw kill the subscription. A malformed payload or a transient SDK throw produces an alert and a logcat entry, and the next command on the same topic is dispatched normally.

  ## Docs

  * The [drones overview](/overview/drones) and the [Cyberwave Edge for DJI driver README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-nodes/cyberwave-edge-dji-mini-android) carry the full alert taxonomy (`driver_action_failed` / `driver_command_rejected` / `driver_aircraft_not_moving` / `driver_dispatch_exception` / `landing_confirmation_required`) and the operator's pre-flight reminder to keep the alerts panel open.
</Update>

<Update label="May 19, 2026">
  ## New Features

  * **Off-RC teleoperation for DJI Mini (Virtual Stick)**: The Cyberwave Edge for DJI Android driver now routes continuous-stick commands (`move_forward` / `move_backward` / `strafe_*` / `turn_*` / `ascend` / `descend`) through DJI MSDK v5's Virtual Stick API, so the same SDK / keyboard surface used to drive the Go2 and the playground simulator drives the real aircraft too. Discrete actions (takeoff, land, RTH, gimbal, set home, compass calibration, reboot, emergency stop) were already wired and continue to work unchanged.

  ### Opt-in gate

  Off-RC teleop is opt-in per twin. Set the following on the twin metadata to enable it:

  ```json theme={null}
  { "drivers": { "default": { "virtual_stick": true } } }
  ```

  Twins without the flag have continuous-stick commands rejected with a `failed` MQTT status — by design, so a phone that paired against a workspace-managed twin without the explicit opt-in cannot drive the aircraft. Discrete actions ship even without the gate.

  The `controller:dji-keyboard:v1` policy carries the requirement under `metadata.requires_twin_metadata`, so the UI can warn before the first keystroke when the gate is missing.

  ### Safety semantics and contention with the physical RC

  * **Stale-command decay.** Continuous targets decay to zero after **500 ms** without a fresh command (lost MQTT link or stuck key → aircraft hovers, not crashes).
  * **Auto-disable.** After **5 s** of continuous zero-velocity the driver hands stick authority back to the physical RC.
  * **The physical RC always wins.** Operator's hardware kill combo (CSC) and any RC stick input immediately reclaim authority — Virtual Stick yields silently.
  * **Automated motion isolates from VS.** Issuing `land` / `return_to_home` / `emergency_stop` shuts Virtual Stick down *before* the automated motion starts, so a stale continuous setpoint can never fight an automated descent.
  * **Active badge.** The frontend renders an **Off-RC teleop ACTIVE** badge whenever Virtual Stick owns the sticks, driven by the `cyberwave/twin/<uuid>/virtual_stick/status` MQTT topic.

  ## SDK

  ### Python SDK

  * **`FlyingTwin` continuous-stick verbs**: `FlyingTwin.move_forward` / `move_backward` / `turn_left` / `turn_right` / `strafe_*` / `ascend` / `descend` are now documented as driving the real DJI aircraft (given the opt-in) — the previous "DJI Mini driver currently drops them" caveat is gone. The `examples/drone_dji_mini.py` walkthrough was updated to demonstrate the live behaviour and the safety story.
  * **`FlyingTwin.pan_camera(angle_deg=…)`**: new high-level helper that pans the camera view by yawing the airframe. The Mini 4 Pro (and the rest of the Mini / Mavic Mini line) ships with a pitch-only mechanical gimbal, so the `yaw` axis on `gimbal_rotate` is silently ignored by the hardware — `pan_camera` is the supported way to change the camera heading on those aircraft. It re-sends `turn_left` / `turn_right` at 5 Hz inside the 500 ms command-stale watchdog and explicitly zeros the yaw axis when the target angle is reached.

  ## Docs

  * The [drones overview](/overview/drones) now documents the off-RC teleoperation opt-in flag, the safety story, and the RC-always-wins contention model alongside the existing PX4 / simulator continuous-stick path.
  * The [Cyberwave Edge for DJI driver README](https://github.com/cyberwave-os/cyberwave/tree/main/cyberwave-edge-nodes/cyberwave-edge-dji-mini-android) carries the full Virtual Stick safety story, the W/S/A/D/Q/E/R/F keyboard layout, and the pre-flight checklist.
</Update>

<Update label="May 6, 2026">
  ## New Features

  * **Edge workflow automation for spatial intelligence**: Added spatial zones, Timed Condition gates, edge-side dwell/timeout/debounce execution, live zone overlays, capture-frame authoring, and compile-time model compatibility checks for camera-frame workflows. This turns intrusion detection and zone-aware perception into an end-to-end workflow pattern across backend, frontend, edge workers, SDK channels, and docs (#2080, #2082, #2085, #2088, #2089, #2093, #2113, #2122, #2153, #2155, #2156).
  * **Datasets and robot recording playgrounds**: Introduced dataset import with Hugging Face/LeRobot focus, dataset slug/visibility/source metadata, SDK schema support, and visualizer/playground pages for LeRobot and Cyberwave-format datasets with episode playback, video panes, URDF/joint context, and long-recording streaming improvements (#2038, #2047, #2051, #2069).
  * **Commerce and template foundations**: Added asset pricing, currency selection, environment monthly cost previews, hardware purchase/rental guidance, organization billing details, delivery addresses, and richer environment/workflow template publishing and cloning flows (#2068, #2101, #2111, #2119, #2154).
  * **New edge/device integrations**: Added the first DJI Mini Android app with DJI telemetry, WebRTC video, Cyberwave MQTT/REST streaming, APK publishing, and smoke-test CI; added a native microphone driver with Whisper STT cloud-model wiring; added the PI05 OpenArm cloud node; and improved GO2 ROS 2 driver setup for dynamic IPs (#2096, #2117, #2004, #2026, #2097).

  ## Feature Improvements

  ## Platform

  * **Workflow authoring polish**: Workflow creation can start from templates or generated mission waypoints; the environment workbench, node library, canvas previews, node I/O strips, wired/available port grouping, missing-configuration hints, hover tooltips, and right-side inspector were substantially refined for faster graph authoring (#2048, #2052, #2065, #2077, #2079, #2081, #2086, #2087, #2115, #2120, #2123, #2128).
  * **Workflow semantics and edge sync clarity**: Workflows now derive environment behavior from bindings instead of the legacy `kind` field, support multi-twin perception on edge, publish `sync_workflows` immediately when run-on-edge workflows activate, and expose operator-triggered sync from the twin editor plus an `--edge-active` CLI filter (#2054, #2071, #2090, #2063, #2112, #2114).
  * **Environment and template UX**: The create-environment flow was redesigned into a full-screen multi-step experience, AI environment creation now opens the assistant on a blank environment, public templates clone correctly across workspaces, and template publishing supports public/workspace visibility with workflow summaries (#2053, #2059, #2060, #2119, #2154).
  * **Edge device observability**: The Edge Devices tab now follows live MQTT heartbeats, shows host/IP/uptime/stream health, filters archived tombstones, uses a compact row layout, and updates backend edge heartbeat state from `edge_health` messages (#2137, #2140, #2141).
  * **Model and catalog UX**: ML models now expose a typed edge runtime selector; the model picker has higher-contrast filters, tokenized search, and greys out edge-incompatible models in camera-frame chains with clear reasons and override affordances (#2076, #2146, #2155).
  * **Operator controls**: Added cloud-recording toggles per twin, an alert-overlay visibility toggle, live-mode hardware-dialog suppression when hardware already exists, improved onboarding overlay dark-mode readability, and route-safe environment creation redirects (#2046, #2095, #2147, #2151, #2158, #2145, #2099).

  ## SDK

  ### Python SDK

  * **Perception/runtime correctness**: ONNX YOLO postprocessing now applies per-class NMS; MQTT topic handlers are deduped to prevent WebRTC answer/candidate storms; annotate publishes overlay payloads on a dedicated frame overlay channel; and device fingerprinting has safer hostname fallbacks (#2133, #2153, #2140).
  * **Dataset and media support**: Python SDK schemas and bindings were updated for dataset import/visualization flows, and camera streaming paths gained stronger reconnect behavior for long-lived WebRTC sessions (#2038, #2051, #2069, #2130).
  * **Internal distribution hardening**: Video-sync packaging was obfuscated, CLI/internal install scripts gained better Buildkite authentication and redaction, and `sync-assets` can filter by `--registry-vendor` for workspace-scoped catalog syncs (#2036, #2157).

  ### C++ SDK

  * **API compatibility maintenance**: Updated the generated assets client call shape after pricing filters expanded the list-assets API, and kept C++ recording pipeline CI coverage aligned with the release (#2068).

  ## Bug Fixes

  * Fixed workflow execution reading stale replica data by forcing primary reads in workflow task paths.
  * Fixed missing `action_id` errors in generated `move_twin` workflow code.
  * Fixed workflow editor autosave races, Send Alert target-twin persistence, Timed Condition alias schema emission, node-title font/spacing issues, and spatial-filter inspector action layout.
  * Fixed AI environment creation hitting a shadowed backend endpoint, public template clone 403s, and wrong redirects after environment creation.
  * Fixed attachment ACL gaps, including environment-map parent access handling.
  * Fixed long robot recordings crashing playback by streaming signed Parquet data around the seek point.
  * Fixed edge worker install/build regressions by installing the local SDK wheel with required extras and smoke-testing `ultralytics`/`zenoh`.
  * Fixed edge workflow codegen bugs around detection confidence, empty twin UUID chains, spatial-filter bbox normalization, alert dedupe bypass for re-firing cooldowns, anonymize fail-closed behavior, and cloud-vs-edge model gate scope.
  * Fixed edge-core worker lifecycle issues: no unnecessary worker image pull when no active workflows exist, two-strike stale-worker cleanup, symmetric worker restart after edge-core restart, and graceful `docker stop` semantics.
  * Fixed CLI MQTT `topic_prefix` forwarding so workflow sync commands reach prefixed edge deployments.
  * Fixed camera driver WebRTC streams going silent after consumers disconnect, and fixed SDK MQTT handler accumulation that caused repeated WebRTC answers/candidates.
  * Fixed Edge Devices status drift, stale online fallbacks, cross-workspace tombstone visibility, and unresolved-edge status rendering.
  * Fixed GO2 driver dynamic-IP handling and filtering of simulated teleop commands.
  * Fixed the DJI Android smoke-test/degraded-mode path, Sentry empty-DSN startup crash, and CI emulator working-directory issues.
  * Fixed live-mode hardware dialog false positives by checking MQTT, REST, and historical edge-device presence.
  * Fixed onboarding overlay dark-mode contrast and removed an exposed close button.
  * Removed a sensitive token from Terraform configuration.
</Update>

<Update label="April 16, 2026">
  ## New Features

  * **Multi-runtime Edge ML inference**: Edge workers can now run models through a runtime registry covering ONNX, TFLite (including quantized/INT8 paths), OpenCV DNN, TensorRT, and PyTorch, with normalized detection publishing across runtimes.
  * **Mission orchestration foundation**: Introduced the initial Mission model/renaming and planning primitives that connect mission authoring/execution flows across backend, frontend, and runtime paths.
  * **Replay intelligence overlays**: Added timeline event APIs and UI markers for alerts + telemetry, including twin-level filtering for replay investigations.
  * **Database-backed feature flag platform**: Replaced hardcoded flags with a DB catalog and added global, organization, and user-level rollout controls with explicit precedence.
  * **Uptime Kuma infrastructure**: Added a dedicated GCP Uptime Kuma stack with dev/staging/production environments and HTTPS-only access for platform monitoring.

  ## Feature Improvements

  ## Platform

  * **Shared-view performance and reliability**: Environment viewer requests now pass a dedicated view token header, isolate viewer query caches, and skip unnecessary data/subscriptions in view-only mode.
  * **Public website messaging polish**: Iterated homepage narrative and interactive hero/code showcase for a simpler, higher-clarity value proposition.
  * **Simulation and vision UX upgrades**: Improved virtual camera live-feed support and added camera FOV cone visualization in 3D environments.
  * **Catalog and seeding maintenance**: Refactored controller/model seed catalogs and updated OpenARM references for staging/prod compatibility.

  ## SDK

  ### Python SDK

  * **Regression hardening for critical paths**: Added integration coverage for `get_latest_frame()` image validity and slash-style `registry_id` twin resolution.
  * **Runtime protocol upgrades**: Backend MQTT client path moved to MQTT v5 semantics with expanded logging/reason-code handling.

  ### C++ SDK

  * **MQTT adapter modernization**: Transitioned from Paho to libmosquitto to improve maintainability and throughput behavior, especially for larger payload handling.
  * **Spec-alignment fixes**: Updated assets API client behavior to match current OpenAPI expectations.

  ## Bug Fixes

  * **Twin replay correctness on long recordings**: Fixed an issue where the digital twin would freeze or snap to a stale pose when scrubbing far from the currently-loaded segment of long robot recordings (90 min+ at 30 Hz). The replay timeline now greys out and shows a "Loading robot data..." indicator while the parquet window for the new segment is being fetched, and scrub clicks are ignored during the load to prevent racing the in-flight request. <Tooltip tip="stub">stub</Tooltip>
  * **Replay parquet load time**: Robot recordings up to \~110 minutes at 30 Hz now load once (typically 1-3 seconds) and then scrub instantly across the entire recording. Previously, every scrub triggered a fresh range fetch that re-downloaded the parquet footer + dictionary pages, making large recordings feel "stuck". The play button is also no longer blocked on the initial fetch — playback starts immediately and the timeline overlay communicates the warm-up state. <Tooltip tip="stub">stub</Tooltip>
  * **Replay spinner stuck on idle recordings**: Fixed an issue where loading a robot recording would leave the timeline frozen on "Loading robot data..." until the user clicked Play. The parquet loader now starts fetching the moment a recording is opened (not lazily on the first play tick), so the warm-up overlay clears as soon as the data is in cache. <Tooltip tip="stub">stub</Tooltip>
  * **Multi-recording replay correctness**: Fixed two related bugs when multiple robot recordings are loaded together. Previously, only the first recording's parquet data was loaded (subsequent recordings for the same twin were silently discarded), and the timeline spinner would stay stuck forever when scrubbing to a segment belonging to a second recording. Parquet windows are now scoped per-recording, so every recording in a multi-session timeline loads and plays independently. The window cache also incrementally diffs across selection changes, so adding a recording to a multi-recording session no longer aborts and restarts the in-flight parquet fetch for the recording that was already loaded. <Tooltip tip="stub">stub</Tooltip>
  * Removed MCP `cw_edit_position` 2m delta guardrail that was blocking large one-shot moves.
  * Fixed UGV replay recording path by ensuring sensor identity and sync-frame publication.
  * Fixed large ZIP asset sync regressions and added dedicated regression coverage for symlink/large-upload edge cases.
  * Fixed Python SDK crash when `environment_id`/`workspace_id` were passed explicitly to `Cyberwave()`
  * Fixed Python SDK asset lookup failure for slash-form registry IDs when aliases are present.
  * Fixed `Camera.start_streaming()` failures in notebook runtimes with active event loops.
  * Fixed controller-policy asset preselection clearing on edit due to loading/search timing.
  * Fixed edit-mode camera panel defaults and depth-visualization rendering conditions.
  * Fixed UGV driver reconnect stability and servo joint-state sync drift.
  * Fixed TFLite resize fallback in environments without Pillow/OpenCV dependencies.
</Update>

<Update label="April 9, 2026">
  ## New Features

  * **3D editing keeps physics active for GLB and URDF twins**: Both `GLBAsset` and `URDFAsset` updated so Rapier rigid bodies remain mounted while edit gizmos are shown, instead of disabling physics during transforms.
  * **Editor-mode-only transform controls**: `EnvironmentViewer3D` now gates `isEditing` and `transformMode` with `isEditorMode`, preventing edit controls from appearing in non-editor contexts.

  ## Feature Improvements

  * **Safer pickability while gizmos are visible**: `setObjectTreePickable(...)` logic tightened in both asset renderers so object picking is disabled when transform gizmos are active, reducing accidental scene interaction conflicts.
  * **More predictable gizmo visibility outside editor mode**: New tests assert that selected GLB/URDF twins in simulate mode receive `isEditing: false` and `transformMode: undefined`, keeping gizmos hidden outside editor mode.
  * **Regression coverage for fixed-base physics in edit flows**: New GLB and URDF tests verify fixed-body Rapier behavior remains active while PivotControls are visible.
</Update>

<Update label="April 8, 2026">
  ## New Features

  * **Mission authoring and execution upgrade**: Redesigned waypoint editing/ordering in UI, better waypoint visualization, drag-and-drop ordering, and waypoint-style in-scene transform gizmos for assets.
  * **Mission capture persistence + workflow integration**: Capture state and media now persist across backend, edge, and frontend; mission captures are surfaced in UI and connected to workflow attachment processing.
  * **Primitives as a first-class concept**: New public endpoint `GET /api/v1/assets/primitives`, SDK access via `cw.assets.list_primitives()`, MCP tooling, and docs updates for environment editing.
  * **Alert categories (business vs technical)**: Backend model/schema/migration/API updates, MQTT payload inclusion, Python SDK support, and docs update.
  * **GO2 runtime pipeline restoration**: End-to-end real-robot path and navigation timestamp handling updates under the new structure.

  ## Feature Improvements

  **SDK**

  * **Python SDK**: Added `AssetManager.list_primitives()` for alias-based primitive discovery (e.g. camera, lidar) with README usage examples.
  * **Python SDK alerts**: Category support added to alert create/update flows, aligned with backend alert categories.
  * **C++ SDK**: Core/runtime parity and route fixes, build/install/guard improvements, and README/docs refresh.

  **Platform**

  * **MQTT documentation**: Major rewrite of MQTT topic/payload reference with cross-linking from driver docs.
  * **Consistent "Add" menus**: Environment header and twin-list menus now share aligned items, icons, and action wiring.
  * **Controller selection UX**: Dedicated-first ordering, "See all" for universal controllers, and clearer "Unassign Controller" language/styling.

  ## Bug Fixes

  * **Replay timeline**: Resolved previously unclickable areas in the timeline.
</Update>
