Skip to content

docs(plans): BEAST-01 cockpit parity & command surfaces plan - #156

Closed
Coldaine wants to merge 1 commit into
mainfrom
docs/beast-cockpit-parity-plan
Closed

docs(plans): BEAST-01 cockpit parity & command surfaces plan#156
Coldaine wants to merge 1 commit into
mainfrom
docs/beast-cockpit-parity-plan

Conversation

@Coldaine

@Coldaine Coldaine commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

User description

Corrected master plan for the human-driven command deck, written against current main after the monorepo cutover.

What this plan is:

  • Phase 0: monorepo cutover deploy to the Jetson + cockpit bridge bring-up (rosbridge globs, Tailscale Serve WSS, Doppler)
  • Phase 1: verified parity with the stock Waveshare web UI (drive, lights, gimbal, PT cam feed, speed control) + e-stop rewire to /ugv/set_allow_motion\ (deletes the browser heartbeat theater from client.ts)
  • Phase 2: surface extensions (snapshot, fullscreen, gamepad, touch joystick, connection HUD)
  • Phase 3: OAK-D spatial overlays (amber /camera/scan, cat-whiskers HUD, threat-horizon ribbon; stretch: isobars, 2.5D voxels)

Ground truth corrections baked in:

Out of scope (next plan): LLM/agent layer, Nav2 goals, SLAM, UPS I2C bench session.


CodeAnt-AI Description

Define the implementation plan for cockpit parity and robot command surfaces

What Changed

  • Adds a corrected plan for deploying the monorepo cockpit bridge to the Jetson and connecting the Hangar cockpit over Tailscale WSS, with a LAN fallback.
  • Defines parity work for driving, lights, gimbal, live camera feeds, voltage, and variable speed control, plus light presets and PT camera support.
  • Replaces browser-managed e-stop heartbeat behavior with robot-side latched motion authority, including explicit ARMED, DISARMED, and LOCKED states and confirmed failure reporting.
  • Plans snapshots, fullscreen feeds, gamepad and touch controls, connection status, and OAK-D spatial overlays.
  • Records current repository, sensor, startup, deployment, validation, and out-of-scope decisions so later implementation phases use the corrected system state.

Impact

✅ Clearer robot motion safety states
✅ Verified cockpit drive and camera parity
✅ Safer, confirmed emergency disarm behavior

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary

Adds the corrected BEAST cockpit implementation plan after the monorepo cutover.

Plan coverage

Phase Scope
0 Jetson deployment and cockpit bridge bring-up
1 Waveshare UI parity: drive, lights, gimbal, PT camera, speed control, and e-stop
2 Snapshot, fullscreen, gamepad, touch joystick, and connection HUD
3 OAK-D spatial overlays and stretch goals

The plan documents the corrected ROS workspace location, preserved LD19 and OAK-D Lite pipelines, motion-enabled startup, interlock-on-detection, robot-side latched e-stop authority, and Tailscale WSS bridge exposure.

LLM and VLM features, Nav2 goals, SLAM, and UPS I2C work remain out of scope. It also supersedes stale planning content from PR #152.

Reflects PR #153 (ROS workspace merged into robot/beast/ros2_ws) and
PR #155 (motion-enabled startup + interlock-on-detection). E-stop rewires
to /ugv/set_allow_motion; browser heartbeat theater deleted. LiDAR
(480 bins, 225-315 crop) and OAK-D Lite pipeline verified preserved on main.
Copilot AI review requested due to automatic review settings August 3, 2026 07:39
@codeant-ai

codeant-ai Bot commented Aug 3, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR 3faeb68 Aug 03, 2026 · 07:39 07:40

@codeant-ai

codeant-ai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds a detailed plan for BEAST cockpit parity. It covers deployment, motion safety, bridge connectivity, control surfaces, OAK-D overlays, exclusions, risks, validation, and open implementation questions.

Changes

BEAST cockpit parity and surfaces

Layer / File(s) Summary
Scope and target architecture
docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md
Defines cockpit parity scope, motion authority, command paths, telemetry, imagery, bridge transport, and excluded work.
Deployment and control surfaces
docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md
Documents workspace cutover, bridge bring-up, parity controls, motion-state handling, UI controls, and OAK-D overlays.
Operational validation and open questions
docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md
Lists operational risks, mitigations, validation requirements, and implementation-time questions.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Suggested reviewers: copilot

Poem

A rabbit maps the cockpit wide,
With safety latches at its side.
Bridges glow and sensors sing,
OAK-D paints each spatial ring.
“Hop through the checks!” the rabbit cries.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the plan but omits most required template sections, including branch scope, review, documentation workflow, validation, and rollback. Complete all required template sections, including branch scope, PR shape, independent review, documentation cleanup, validation, and risk/rollback.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the documentation change and its focus on BEAST cockpit parity and command surfaces.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/beast-cockpit-parity-plan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new planning doc for bringing BEAST-01’s Hangar /cockpit to parity with the stock Waveshare UI and then extending it, including a Phase 0 Jetson monorepo cutover + rosbridge/WSS bring-up and a Phase 1 e-stop redesign toward robot-side latched motion authority.

Changes:

  • Introduces a phased implementation plan covering deployment cutover, cockpit parity (drive/lights/gimbal/cameras/voltage), and UI surface extensions.
  • Documents updated ground truth about repo topology, current robot deployment state, and motion-enabled startup behavior.
  • Specifies intended safety/control semantics (ARMED/DISARMED/LOCKED) and validation steps for each phase.
Suppressed comments (1)

docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md:99

  • This phase-0 step suggests adding /ugv/set_allow_motion to services_glob, but the current cockpit bridge configuration sets SERVICES_GLOB = '[]' and the cockpit_rosbridge wrapper removes service/action ops entirely. If the plan’s DISARM/RE-ARM path stays service-based, this step should explicitly call out the required bridge/protocol change (or an alternate relay), not just a services_glob edit.
4. Author the rosbridge glob whitelist in `rosbridge.launch.py`: exactly the topics/services in
   `client.ts` `ROS_SUBSCRIPTIONS`/`ROS_PUBLICATIONS` plus service `/ugv/set_allow_motion`
   (`services_glob`). The bridge fault rail in the UI will confirm refusals.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +53 to +59
1. **E-stop = robot-side latched service.** The cockpit DISARM button calls
`/ugv/set_allow_motion` (`{data: false}`); re-arm calls `{data: true}`. Rendered state comes
only from `/ugv/allow_motion` + `/cockpit/status` interlock fields — never from local
intent. The 2 Hz heartbeat, intent latching, beforeunload trap, and keep-socket-alive
machinery in `client.ts` are deleted. Rationale: twist_mux lock topics are VOLATILE and
don't survive mux restart (documented in `twist_mux.yaml`); the service flag lives in
`ugv_bringup` below the mux, gates the serial write itself, and covers every command source.
Comment on lines +90 to +92
**Check the systemd unit's launch args during cutover** — it currently passes
`allow_motion:=false`; the new code defaults `true`. Decide the unit's args deliberately
(recommend: let the new default stand; interlocks still disarm).
## Phase 1 — Parity: drive, lights, gimbal, cameras + e-stop rewire

**Verify-then-fix each control end-to-end** (robot untethered, pack ≥ 10.5 V, supervised):
1. Drive: WASD + hold-pad at 10 Hz lands on `/cmd_vel`; release → watchdog stop ≤ 0.5 s.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md`:
- Around line 203-208: The Validation section must verify the rosbridge service
whitelist, not just topics_glob. Inspect services_glob and use the actual WSS
client to execute both DISARM and RE-ARM for /ugv/set_allow_motion, recording
successful responses, timeout behavior, and denial of an unwhitelisted service;
retain the existing topic and ROS checks.
- Around line 53-63: Add freshness requirements to the motion-state contract
covering `/ugv/allow_motion` and `/cockpit/status`: track each stream’s age,
render UNKNOWN or UNCONFIRMED when either exceeds the defined threshold, and
prevent RE-ARM until both streams are fresh again. Update the motion-state and
RE-ARM behavior in the plan while preserving the existing ARMED, DISARMED, and
LOCKED semantics for fresh data.
- Around line 79-80: Resolve the rosbridge address inconsistency across the “WSS
via Tailscale Serve” description and the LAN fallback URL: either configure
rosbridge to bind to the controlled LAN interface, documenting the required
firewall rules, or replace the 192.168.0.187:9090 fallback with a local
forwarding path. Before Phase 0 completion, test the exact fallback connection
and document the selected behavior consistently.
- Around line 90-94: Update the cutover plan to make the beast-ros-base.service
launch-argument change mandatory: remove or change allow_motion:=false so the
new true default produces the intended ARMED-at-boot behavior. Add explicit
post-restart verification of the effective launch argument and
/ugv/allow_motion, while retaining the existing safety interlock checks.
- Around line 32-38: Update the motion/interlock design around the robot-side
safety state and related sections to specify that clearing ETHERNET_LOCK or
CHARGING_LOCK does not automatically re-arm motion: allow_motion remains false
until an explicit operator RE-ARM, while preserving the existing 2-second RE-ARM
hold. Add robot tests covering both interlock-clear transitions and requiring
explicit RE-ARM before motion is restored.
- Around line 97-105: Update the rosbridge and deployment plan around
ROS_SUBSCRIPTIONS, ROS_PUBLICATIONS, services_glob, Tailscale Serve, and
BEAST_COCKPIT_WS_URL to define endpoint authorization controls, including an
operator/device allowlist, restricted Tailscale access, and disabling the LAN
fallback except on an isolated bench. Add verification that unauthorized clients
cannot publish, actuate, or call /ugv/set_allow_motion.
- Around line 156-160: Update the depthimage_to_laserscan plan entry to document
that /camera/scan uses /oak/stereo/image_raw with /oak/stereo/camera_info,
including the source camera-topic remap. Add a pre-enable validation requiring
non-zero P.D0 values and valid camera range data, and retain the existing USB
bandwidth checks.
- Around line 167-169: Update the “Threat-horizon ribbon” plan to use a
depth-preserving transport or server-side metric depth topic instead of relying
on the JPEG compressed image. Document the metric topic contract, including byte
order, scale, and clipping values, with depths below 0.3 m clipped consistently
for ribbon and HUD thresholds.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7c47553c-a372-4f03-912e-7ac1be533e81

📥 Commits

Reviewing files that changed from the base of the PR and between 60fc95d and 3faeb68.

📒 Files selected for processing (1)
  • docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md

Comment on lines +32 to +38
**Boot/arm design changed: motion-enabled startup (PR #155, merged 2026-08-03).**
`bringup_lidar.launch.py` now declares `allow_motion` with `default_value='true'`. The robot
boots **motion-enabled**; `ugv_safety_monitor` disarms only when an interlock (Ethernet
carrier / charging) is observed, calling `/ugv/set_allow_motion` (`std_srvs/SetBool`) — still
the sole motion authority in `ugv_bringup`. `interlock_override` exists as a startup-only
maintenance escape hatch (never a service, never default true). **There is no boot-ARM gate
to design around — the earlier "boots disarmed" assumption is dead.**

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate target file =="
fd -a '2026-08-03-beast-cockpit-parity-and-surfaces\.md' . || true

echo "== target excerpt =="
if [ -f docs/plans/2026-08-03-beast-cookpit-parity-and-surfaces.md ]; then
  rm -f docs/plans/2026-08-03-beast-cookpit-parity-and-surfaces.md 2>/dev/null || true
fi
cat -n docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md | sed -n '1,120p'

echo "== related searches =="
rg -n "RE-ARM|re-arm|REARM|hold|2[- ]?second|allow_motion|ugv_safety_monitor|set_allow_motion|interlock|charging|Ethernet|motion_enabled|bringup_lidar|2026-08-03" docs . --glob '!*.git' --glob '!build/**' --glob '!dist/**' | head -n 300

Repository: Coldaine/RobotOverview

Length of output: 50381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p=Path('docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md')
print('target_path_exists=', p.exists())
if p.exists():
    text=p.read_text()
    for needle in ["interlock", "RE-ARM", "re-ARM", "REARM", "operator", "allow_motion", "motion-enable", "charging", "Ethernet"]:
        print(f'{needle}:', text.count(needle), [i for i,l in enumerate(text.splitlines(),1) if needle.lower() in l.lower()][:20])
PY

Repository: Coldaine/RobotOverview

Length of output: 561


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate implementation candidates =="
fd -i 'safety_monitor|bringup_lidar|ugv_bringup|cockpit/status|command.*rail|client\.ts|beast_status' . | sed -n '1,120p'

echo "== focused safety/status/arm files =="
for f in $(fd -i 'safety_monitor|cockpit_status|bringup_lidar|command.*rail|client\.ts|beast_status' . | sed -n '1,40p'); do
  echo "--- $f ($(wc -l < "$f") lines) ---"
  rg -n "allow_motion|set_allow_motion|ETHERNET|CHARGING|charging|RE-ARM|re-arm|hold|2 s|2s|interlock|LOCKED|LOCK" "$f" || true
done

echo "== structural calls to safety/status status =="
rg -n "safety/status|allow_motion|set_allow_motion|ETHERNET_LOCK|CHARGING_LOCK" robot/docs/src src public . --glob '!**/.git/**' --glob '!docs/plans/**' --glob '!src/data/**' | head -n 300

Repository: Coldaine/RobotOverview

Length of output: 50378


Specify explicit motion recovery after Ethernet or charging clears.

The robot-side logic does not re-arm after an interlock state clears. This does not change the 2-second RE-ARM hold; it only documents the missing transition. State that clearing ETHERNET_LOCK or CHARGING_LOCK leaves allow_motion=false until an explicit operator RE-ARM, and cover this behavior in the robot tests.

Also applies to: 53-63

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 32 -
38, Update the motion/interlock design around the robot-side safety state and
related sections to specify that clearing ETHERNET_LOCK or CHARGING_LOCK does
not automatically re-arm motion: allow_motion remains false until an explicit
operator RE-ARM, while preserving the existing 2-second RE-ARM hold. Add robot
tests covering both interlock-clear transitions and requiring explicit RE-ARM
before motion is restored.

Comment on lines +53 to +63
1. **E-stop = robot-side latched service.** The cockpit DISARM button calls
`/ugv/set_allow_motion` (`{data: false}`); re-arm calls `{data: true}`. Rendered state comes
only from `/ugv/allow_motion` + `/cockpit/status` interlock fields — never from local
intent. The 2 Hz heartbeat, intent latching, beforeunload trap, and keep-socket-alive
machinery in `client.ts` are deleted. Rationale: twist_mux lock topics are VOLATILE and
don't survive mux restart (documented in `twist_mux.yaml`); the service flag lives in
`ugv_bringup` below the mux, gates the serial write itself, and covers every command source.
2. **Motion states shown in the UI:** ARMED (default at boot) / DISARMED (operator or
interlock) / LOCKED (hardware interlock observed: Ethernet or charging). No ARM-from-boot
flow exists — PR #155 removed it. DISARM is one click, immediate; RE-ARM requires a 2 s
hold-to-confirm so a dropped click never re-enables motion.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add freshness handling to the motion-state contract.

Rendering state from /ugv/allow_motion and /cockpit/status is safe only when both streams are fresh. The plan defines a failed service-call state, but not a stale-telemetry state. A cached true can leave the UI showing ARMED after status delivery stops. Add age thresholds, render UNKNOWN or UNCONFIRMED for stale data, and block RE-ARM until fresh state returns.

Also applies to: 126-131

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 53 -
63, Add freshness requirements to the motion-state contract covering
`/ugv/allow_motion` and `/cockpit/status`: track each stream’s age, render
UNKNOWN or UNCONFIRMED when either exceeds the defined threshold, and prevent
RE-ARM until both streams are fresh again. Update the motion-state and RE-ARM
behavior in the plan while preserving the existing ARMED, DISARMED, and LOCKED
semantics for fresh data.

Comment on lines +79 to +80
WSS via Tailscale Serve → rosbridge :9090 (loopback on Jetson)
Robot guarantees that do NOT depend on the UI:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Resolve the rosbridge bind-address contradiction.

Lines 79-80 describe rosbridge as loopback-only. Lines 103-105 use ws://192.168.0.187:9090 as a LAN fallback. If rosbridge binds only to 127.0.0.1, this fallback cannot connect. Either bind rosbridge to a controlled LAN interface and document the firewall rules, or replace the fallback with a local forwarding path. Test the exact fallback URL before Phase 0 is complete.

Also applies to: 103-105

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 79 -
80, Resolve the rosbridge address inconsistency across the “WSS via Tailscale
Serve” description and the LAN fallback URL: either configure rosbridge to bind
to the controlled LAN interface, documenting the required firewall rules, or
replace the 192.168.0.187:9090 fallback with a local forwarding path. Before
Phase 0 completion, test the exact fallback connection and document the selected
behavior consistently.

Comment on lines +90 to +94
**Check the systemd unit's launch args during cutover** — it currently passes
`allow_motion:=false`; the new code defaults `true`. Decide the unit's args deliberately
(recommend: let the new default stand; interlocks still disarm).
2. Verify ground truth post-cutover: `/scan` ~10 Hz / 480 ranges, `/ugv/allow_motion` true,
watchdog armed, `ETHERNET_LOCK` appears on `/ugv/safety/status` when the cable is in.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make the effective boot state explicit.

beast-ros-base.service currently passes allow_motion:=false. That argument overrides the new launch default true, so the ARMED-at-boot contract and validation step will not occur if the unit is deployed unchanged. Make the systemd unit update mandatory, or change the plan to expect DISARMED at boot. Verify the effective launch argument and /ugv/allow_motion after restart.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 90 -
94, Update the cutover plan to make the beast-ros-base.service launch-argument
change mandatory: remove or change allow_motion:=false so the new true default
produces the intended ARMED-at-boot behavior. Add explicit post-restart
verification of the effective launch argument and /ugv/allow_motion, while
retaining the existing safety interlock checks.

Comment on lines +97 to +105
4. Author the rosbridge glob whitelist in `rosbridge.launch.py`: exactly the topics/services in
`client.ts` `ROS_SUBSCRIPTIONS`/`ROS_PUBLICATIONS` plus service `/ugv/set_allow_motion`
(`services_glob`). The bridge fault rail in the UI will confirm refusals.
5. Tailscale Serve: proxy HTTPS:443 → `localhost:9090` on `beast-01`; verify
`wss://beast-01.<tailnet>.ts.net` upgrades a WebSocket from the workstation.

**Hangar:**
6. Doppler `homelab`/`dev` (+`prd`): `BEAST_COCKPIT_WS_URL=wss://beast-01.<tailnet>.ts.net`.
Keep a documented LAN fallback (`ws://192.168.0.187:9090`) for bench bring-up.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repo files around target:"
git ls-files | rg 'docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces\.md|rosbridge|client\.ts|tailnet|Tailscale|doppler|serve|lan|fallback' || true

echo
echo "Target plan excerpt:"
sed -n '1,160p' docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md

echo
echo "Search for auth/allowlist/service definitions:"
rg -n --hidden --glob '!*.lock' 'rosbridge|--allow-(topics|services)|allowed-(topics|services)|services_glob|ROS_SUBSCRIPTIONS|ROS_PUBLICATIONS|allow_motion|Tailscale|serve|doppler|BEAST_COCKPIT_WS_URL|fallback|acl|allowlist|authentication|auth' . | sed -n '1,240p'

Repository: Coldaine/RobotOverview

Length of output: 50381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant documents and files:"
printf '\n--- docs/deploy.md excerpt ---\n'
sed -n '45,70p' docs/deploy.md || true
printf '\n--- .claude/skills/beast-paces/SKILL.md excerpts ---\n'
sed -n '34,38p;53,56p' .claude/skills/beast-paces/SKILL.md || true

printf '\nSearch only for rosbridge launch args/services_glob/allow_topics/topics_glob/auth-related terms:\n'
rg -n \
  'rosbridge\.launch\.py|services_glob|topics_glob|allow_topics|topics_whitelist|topics_blacklist|allow_auth|auth|Tailscale|TAILSCALE|serve|ts\.net|acl|allowlist|whitelist|DENY|DISALLOW|allow_motion:=' \
  docs .claude package.json package-lock.json src robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/launch/rosbridge.launch.py 2>/dev/null || true

printf '\nRosebridge launch file excerpt:\n'
sed -n '1,220p' robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/launch/rosbridge.launch.py || true

Repository: Coldaine/RobotOverview

Length of output: 50381


Define authorization access controls for the rosbridge endpoint.

ROS_SUBSCRIPTIONS/ROS_PUBLICATIONS and rosbridge service globs only limit ROS names. Tailscale Serve and the documented LAN fallback also enable drive, actuator, and /ugv/set_allow_motion calls. Add explicit controls such as a Tailscale ACL/operator or device allowlist, disable the LAN URL outside an isolated bench, and verify that unauthorized clients cannot publish or call the service.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 97 -
105, Update the rosbridge and deployment plan around ROS_SUBSCRIPTIONS,
ROS_PUBLICATIONS, services_glob, Tailscale Serve, and BEAST_COCKPIT_WS_URL to
define endpoint authorization controls, including an operator/device allowlist,
restricted Tailscale access, and disabling the LAN fallback except on an
isolated bench. Add verification that unauthorized clients cannot publish,
actuate, or call /ugv/set_allow_motion.

Comment on lines +156 to +160
1. Add `depthimage_to_laserscan` (`ros-humble-depthimage-to-laserscan`) on
`/oak/stereo/image_raw` → `/camera/scan` (squashes 3D overhangs to a 2D forward arc).
Note USB3 cable is PENDING — on USB2 verify bandwidth with RGB + depth + scan live before
enabling all three; degrade depth rate first.
2. Verify `/cockpit/depth/compressed` + `/cockpit/overhead_clearance` live (nodes exist, unverified).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 \
  'depthimage_to_laserscan|oak/stereo/(image_raw|camera_info)|camera_info' \
  robot/beast/ros2_ws

Repository: Coldaine/RobotOverview

Length of output: 14438


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md robotics robot/beast/ros2_ws/src/ugv_main/ugv_gazebo/config/ros_gz_bridge.yaml robot/beast/ros2_ws/src/ugv_main/ugv_main/ugv_vision/launch/oak_d_lite.launch.py robot/beast/ros2_ws/src/ugv_main/ugv_vision/config/params.yaml robot/beast/ros2_ws/src/ugv_main/ugv_vision/config/camera_info.yaml robot/beast/ros2_ws/deploy/storage/mission.topics | sed -n '1,120p'

echo "== plan context =="
cat -n docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md | sed -n '130,175p'

echo "== rtabmap launch =="
cat -n robot/beast/ros2_ws/src/ugv_main/ugv_slam/launch/rtabmap.launch.py | sed -n '1,90p'

echo "== localization launch =="
cat -n robot/beast/ros2_ws/src/ugv_main/ugv_nav/launch/nav_bringup/localization_launch.py | sed -n '70,100p'

echo "== gazebo bridge =="
cat -n robot/beast/ros2_ws/src/ugv_main/ugv_gazebo/config/ros_gz_bridge.yaml | sed -n '30,50p'

echo "== camera config =="
cat -n robot/beast/ros2_ws/src/ugv_main/ugv_vision/config/params.yaml | sed -n '1,25p'
if [ -f robot/beast/ros2_ws/src/ugv_main/ugv_vision/config/camera_info.yaml ]; then
  cat -n robot/beast/ros2_ws/src/ugv_main/ugv_vision/config/camera_info.yaml
fi

echo "== topic file =="
cat -n robot/beast/ros2_ws/deploy/storage/mission.topics | sed -n '1,30p'

echo "== laser scan references in repo =="
rg -n -C 3 'depthimage_to_laserscan|depth.*laserscan|CameraInfo|camera_info_url|min_distance|max_distance|/camera/scan|/oak/stereo/camera_info' .

Repository: Coldaine/RobotOverview

Length of output: 50378


Document the /oak/stereo/camera_info contract for /camera/scan.

/oak/stereo/image_raw has a matching /oak/stereo/camera_info entry, but the OAK-D static calibration is populated from RGB camera metadata. Add the scan’s source camera topic/remap and the accepted non-zero P.D0/range validation before enabling /camera/scan.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 156
- 160, Update the depthimage_to_laserscan plan entry to document that
/camera/scan uses /oak/stereo/image_raw with /oak/stereo/camera_info, including
the source camera-topic remap. Add a pre-enable validation requiring non-zero
P.D0 values and valid camera range data, and retain the existing USB bandwidth
checks.

Comment on lines +167 to +169
5. **Threat-horizon ribbon**: absolute-positioned canvas strip over the OAK RGB feed, nearest
depth per column mapped blue→red (source: `/cockpit/depth/compressed` frame, downsampled
in-browser; reuse `depth_ops.py` stats if a lighter topic exists).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | rg '(^|/)(docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces\.md|depth_colorizer\.py|depth_ops\.py|depth\.py|.*depth.*\.py)$|cockpit' || true

echo
echo "Doc excerpt:"
if [ -f docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md ]; then
  nl -ba docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md | sed -n '150,185p'
fi

echo
echo "Search depth_colorizer/deep_ops/cockpit depth:"
rg -n --hidden --glob '!*.png' --glob '!*.jpg' --glob '!*.jpeg' --glob '!*.gif' --glob '!*.bmp' 'depth_colorizer|depth_ops|/cockpit/depth/compressed|depth/compressed|topic_name|depth_colorize|depth_ops' . || true

Repository: Coldaine/RobotOverview

Length of output: 3038


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Doc excerpt:"
awk 'NR>=150 && NR<=185 { printf "%5d\t%s\n", NR, $0 }' docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md || true

echo
echo "Definitions/usages around cockpit depth topics:"
rg -n --hidden --glob '!*.png' --glob '!*.jpg' --glob '!*.jpeg' --glob '!*.gif' --glob '!*.bmp' \
  '("|\x27|)(/cockpit/depth/compressed|/cockpit/depth|depth_colorizer|depth_ops|compressed|compressed_image|metric|metric_metric|meters|unit|cm|width|height|msg|depth)("\x27|)' \
  docs robot src || true

echo
echo "Inspect depth_colorizer.py outline and relevant code:"
wc -l robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/depth_colorizer.py robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/depth_ops.py
sed -n '1,260p' robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/depth_colorizer.py
sed -n '1,260p' robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/depth_ops.py

Repository: Coldaine/RobotOverview

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Focused topic/config references:"
rg -n --hidden --glob '!src/**' --glob '!robot/beast/ros2_ws/src/ugv_else/**/*.map' --glob '!*.png' --glob '!*.jpg' --glob '!*.jpeg' --glob '!*.gif' --glob '!*.bmp' \
  '/cockpit/depth/compressed|/cockpit/depth|depth_colorizer|depth_ops|compressed_topic|sensor_msgs/msg/Image|compressed_image|depth_topic|depth_metric|metric' \
  docs robot/src robot/beast/ros2_ws/src/ugv_main robot/beast/ros2_ws/launch robot/beast/ros2_ws/src/ugv_main/ugv_cockpit || true

echo
echo "Plan excerpt:"
awk 'NR>=150 && NR<=185 { printf "%5d\t%s\n", NR, $0 }' docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md || true

echo
echo "Python files relevant excerpt with context:"
for f in robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/depth_colorizer.py robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/depth_ops.py robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/cockpit_rosbridge.py robot/beast/ros2_ws/src/ugv_main/ugv_cockpit/ugv_cockpit/overhead_clearance.py; do
  if [ -f "$f" ]; then
    echo "===== $f ($(wc -l < "$f") lines) ====="
    rg -n 'class |def |topic_name|publish|Image|encode|depth_ops|depth_histogram|compress|topic' "$f" -C 3 || true
  fi
done

Repository: Coldaine/RobotOverview

Length of output: 26378


Define the metric depth topic contract for the threat ribbon.

/cockpit/depth/compressed is documented and implemented as a JPEG sensor_msgs/msg/CompressedImage; the raw millimetre metric values are lost when downsampled in-browser. Add a depth-preserving transport or publish a server-side metric topic, then document byte order, scale, and the 0.3 m clipping behavior so the ribbon and HUD thresholds are reliable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 167
- 169, Update the “Threat-horizon ribbon” plan to use a depth-preserving
transport or server-side metric depth topic instead of relying on the JPEG
compressed image. Document the metric topic contract, including byte order,
scale, and clipping values, with depths below 0.3 m clipped consistently for
ribbon and HUD thresholds.

Comment on lines +203 to +208
## Validation

- Robot (post-cutover): `ros2 topic hz /scan` (~10 Hz, 480 ranges),
`ros2 topic echo /ugv/allow_motion --once`,
`ros2 service call /ugv/set_allow_motion std_srvs/srv/SetBool "{data: false}"` round-trip,
`ros2 param get /rosbridge_websocket topics_glob` shows the whitelist.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate the service whitelist through rosbridge.

Phase 0 configures services_glob, but validation checks only topics_glob. The ROS CLI call in Line 207 bypasses rosbridge, so validation can pass while the browser cannot call /ugv/set_allow_motion. Inspect services_glob and execute DISARM and RE-ARM through the actual WSS client, including response, timeout, and denied-service cases.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md` around lines 203
- 208, The Validation section must verify the rosbridge service whitelist, not
just topics_glob. Inspect services_glob and use the actual WSS client to execute
both DISARM and RE-ARM for /ugv/set_allow_motion, recording successful
responses, timeout behavior, and denial of an unwhitelisted service; retain the
existing topic and ROS checks.

@@ -0,0 +1,224 @@
# Plan: BEAST-01 Cockpit Parity & Command Surfaces

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: This plan supersedes earlier planning content (the July 31 command deck plan and the Aug 1 cockpit roadmap) but does not reference or mark those files as superseded. The docs/plans/ directory has accumulated many dated plan documents that are stale or superseded, and the plans README convention states "Executed plans are deleted, not archived" — yet superseded plans remain in the directory. Consider deleting or explicitly marking the superseded plans (2026-07-31-beast-command-deck-plan.md, 2026-07-31-beast-command-deck-spec.md, 2026-08-01-beast-cockpit-future-roadmap.md) and updating docs/plans/README.md.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@@ -0,0 +1,224 @@
# Plan: BEAST-01 Cockpit Parity & Command Surfaces

**TL;DR**

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: The plans README (docs/plans/README.md) was not updated to include this new plan or to remove superseded entries. The README's "Live work orders" table should list this plan and remove the command deck plan and cockpit roadmap it supersedes.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md 1 Plan supersedes earlier planning content (July 31 command deck plan, Aug 1 cockpit roadmap) but does not reference or mark those files as superseded. The docs/plans/ directory has accumulated many dated plan documents that are stale or superseded, violating the convention in docs/plans/README.md that "Executed plans are deleted, not archived."

SUGGESTION

File Line Issue
docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md 3 The plans README (docs/plans/README.md) was not updated to include this new plan or to remove superseded entries. The README's "Live work orders" table should list this plan and remove the command deck plan and cockpit roadmap it supersedes.
Files Reviewed (1 file)
  • docs/plans/2026-08-03-beast-cockpit-parity-and-surfaces.md - 2 issues

Fix these issues in Kilo Cloud


Reviewed by ling-3.0-flash:free · Input: 248.4K · Output: 31K · Cached: 532.7K

@Coldaine

Coldaine commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Merged into main via commit 3faeb68.

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants