From 6498c14dc255115d6e68711f149243b818a3afc5 Mon Sep 17 00:00:00 2001 From: Grant Date: Wed, 8 Jul 2026 11:14:14 +0200 Subject: [PATCH] docs: CLAUDE.md v3.5 - add VSC terminal label, session log bridge --- CLAUDE.md | 562 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 349 insertions(+), 213 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 049fcee..e900d9a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,249 +1,385 @@ -# Argonaut 3 — ROV Autonomous Inspection System -This file defines how Claude should behave when working in this repository. -Prioritise correctness, safety, and field-operational reliability above all else. -This is a real autonomous vehicle system. Code runs on hardware in water. +# CLAUDE.md — Rules for Claude on the Argonaut 3 Project +**Version:** 3.5 +**Updated:** 8 July 2026 + +**Changelog 3.5:** Added `[VSC]` terminal label. Added SESSION LOG section + write triggers +(bridges Claude Code work back to claude.ai chat, which has no native access to Claude Code +sessions). --- -# Project Identity +## PRIME DIRECTIVES — These override everything else -- **Project:** Argonaut 3 — Autonomous Underwater ROV Inspection System -- **Company:** SymbyTech -- **Vehicle:** Argonaut 3 based on the BlueROV2 Heavy (Blue Robotics) -- **Target:** Hull and jacket surveys, no human operator during field operations -- **Status:** Active development — Phase 2 (dev infrastructure) complete +### 1. Research before acting. Always. +Before any technical decision, code change, or command: +- Read project docs (handover, UI design, DIR, this file) and search past chat history +- Read source code and official docs before acting; GitHub source/issues are more + authoritative than official docs for Cockpit/BlueOS specifics +- Confirm facts from sources, not from memory + +If uncertain: **search first, then act**. Never guess. + +### 2. Time and tokens are finite and valuable +- **Time wasting is FORBIDDEN. Token wasting is FORBIDDEN.** +- Short replies. No preamble padding. To the point. +- Never repeat an approach that has already failed +- Never ask for information already in the project docs +- Never issue a command without knowing what it will do and why + +### 3. Facts only. Never assumptions. +- Do not proceed based on what "should" work +- Do not assume port, routing, or API behaviour — measure it +- Do not infer system state — verify it before issuing commands +- If a claim cannot be verified from a source, say so explicitly +- Never present a prior session's confirmed state as the current running state --- -# Tech Stack +## Working Style -- **Primary language:** Python 3 (ROS2 nodes), C++ reserved for latency-critical paths only -- **Framework:** ROS2 Jazzy Jalisco -- **Vehicle OS:** BlueOS (Blue Robotics) on Raspberry Pi 4 -- **Autonomy compute:** Raspberry Pi 5, Ubuntu 24.04 LTS -- **MAVLink bridge:** MAVROS -- **Container runtime:** Docker (ARM64 images via buildx + QEMU) -- **Registry:** Harbor (self-hosted) — `registry.symbytech.com` -- **Source control:** Gitea (self-hosted) — `git.symbytech.com` -- **GCS:** Cockpit (BlueOS extension) -- **Dev simulation:** BlueOS internal ardupilot-manager SITL (ArduSub 4.5.7) -- **Package manager:** pip (Python), colcon (ROS2 workspace) +### One command at a time +Give one command, wait for feedback, then give the next. Never batch commands unless asked. + +### Lead with context and corrections BEFORE instructions, never after. + +### Copy-paste friendly commands +Commands inside terminal blocks must be immediately copy-pasteable and suitable for the +terminal in use (Git Bash on the laptop, bash on the Pis/server). Never include: +- Placeholders like `` or `path/to/file` +- Hashed `#` comments inside the command block +- Options that require editing before running + +### Code comments +When writing code (Python, config, scripts), always include full inline comments +explaining what each section does and why. This is a standing user preference. +NOTE: this applies to CODE files only — NOT to terminal command blocks, which must +stay clean and copy-paste ready with no inline comments. + +### Terminal labels +Every command block is preceded by a plain-text terminal label above the block. +Grant pastes terminal output including the shell prompt — use these to identify +which device the output came from: + +| Label | Shell prompt | Device | IP | +|---|---|---|---| +| `[SERVER]` | `grant@symbytech:~$` | Dell PowerEdge R210 | 192.168.1.175 | +| `[RPi5]` | `ubuntu@rov-brain:~$` | Raspberry Pi 5 autonomy brain | 192.168.1.101 | +| `[RPi4]` | `pi@blueos:~$` | Raspberry Pi 4 BlueOS gateway | 192.168.1.100 | +| `[LAPTOP — Git Bash]` | `grant@BB8 MINGW64 ...` | Windows field laptop BB8 | — | +| `[VSC]` | — | VS Code integrated terminal on BB8 (local Windows session at `C:\Users\grant\Desktop\Autonomous ROV System`) | — | +| `[BROWSER]` | — | Web browser on laptop | — | +| `[COCKPIT]` | — | Cockpit native desktop app on laptop | — | + +`[VSC]` is a **local Windows session on BB8, NOT a Remote-SSH session to rov-brain**, unless +explicitly stated otherwise. Do not assume `[VSC]` == RPi5 working copy. + +Never put the label inside the bash block. + +> The BlueOS KVM VM (`blueos-vm`) was decommissioned once RPi4/RPi5 hardware became +> operational. `[VM]` is no longer a valid label. Any VM artefacts remaining on the +> server are for reference only. + +### Verify before modifying +Always read a file before modifying it. Always check current state before changing it. +State what you observed before proposing a change. + +### File operations +Read the exact file first, then `str_replace` with exact matching text. Remove old +versions before writing new ones. Complete files, not fragments — no partial code. + +### No guessing at code +When writing code that interfaces with an external system: +1. Find the official documentation or source code +2. Find a working example from the official repo or community +3. Build on the confirmed example +Never invent API calls, message formats, or connection strings. + +### Own mistakes once +Acknowledge an error once and fix it. No repeated apologies, no grovelling. + +### KISS +Recommend the simple correct path, not a menu of options. --- -# Repository Structure - -``` -rov-autonomy/ -├── src/ -│ ├── rov_interfaces/ # Custom ROS2 messages and services — shared contracts -│ ├── rov_navigation/ # State estimation, EKF, depth fusion -│ ├── rov_perception/ # Camera nodes, feature detection -│ ├── rov_control/ # Failsafe monitor, motion controller -│ ├── rov_mission/ # Mission executor, waypoint sequencing -│ ├── rov_bringup/ # Top-level launch files -│ └── rov_simulation/ # DEV ONLY — mock publishers, test scenarios -├── Dockerfile # ARM64 image build — targets RPi5 -├── docker-entrypoint.sh # Container startup — sources ROS2 + workspace -└── CLAUDE.md # This file -``` - -**Critical rule:** `rov_simulation` is dev-only. Never include it in production builds or deploy it to vehicle hardware. +## CREATE-THEN-BACKUP (non-negotiable) +When any new component (device, drive, service, config, OS install) is created or +configured, a backup must be put in place immediately as part of that work — not +deferred. Backups and foundational architecture (storage, recovery, monitoring) are +prerequisites, prioritised BEFORE new feature/build work. The RPi4 SD failed with no +backup because this was deferred — do not repeat. --- -# Core Principles +## Project-Specific Rules -- **Asset preservation over mission completion.** A recovered vehicle can repeat a mission. A lost vehicle cannot. -- **Field-operational from day one.** The same codebase runs in dev and field — environment is selected by config, not by code changes. -- **Safety is continuous, not reactive.** Failsafe monitoring runs at all times, not only on failure. -- **Prefer simple, readable solutions.** This code may be read under pressure in the field. -- **No premature optimisation.** Correctness first, performance when measured. -- **Keep functions small and single-purpose.** -- **Do not introduce new dependencies without explicit approval.** Each dependency is a liability on embedded hardware. +### Cockpit DIY widgets +- Cockpit is **v1.18.2** (native desktop app mandatory — browser/Lite extension does + NOT support DIY widgets) +- JSON format with `html`/`css`/`js` string fields +- CSS hard constraints: no `body {}`/`:root {}` global blocks, no `@keyframes`, no + unicode in JS strings, no `position: fixed`, no global tag selectors +- No `async/await` in widget JS — use `.then()/.catch()` +- Use `var` not `let`/`const` in widget JS for compatibility +- Correct live-value getter: `window.cockpit.getDataLakeVariableData(variableId)` + (CONFIRMED v1.18.2). `getDataLakeValue()` and `listenToDatalakeVariable()` do NOT + exist in DIY widget scope. `getAllDataLakeVariablesInfo()` is metadata-only. +- Widget JSON files in the repo use underscore naming: `w6_altitude.json` (matches + W0–W5). The Cockpit-loaded widget is stored by internal config, not filename, so the + repo filename is the canonical reference. + +### Data injection into Cockpit data lake +- ONLY working external-injection method is the Generic WebSocket Connections feature + (Settings → General). Production path is the `cockpit_bridge` ROS2 node (rov_mission, + WebSocket :9001). +- Message format: `variable-name=value` (one per send). Data lake key: `external/{name}`. +- ALWAYS use hyphens — Cockpit normalises underscores to hyphens in IDs. +- HTTP POST to mavlink2rest does NOT work for data lake injection. MAVLink UDP injection + from external scripts does NOT work. Tested and confirmed — do not suggest them. +- Current data lake variables published by `cockpit_bridge` (19 total — 8 telemetry + 11 mode-profile flags): + +| Variable | Source topic | Meaning | +|---|---|---| +| `external/rov-failsafe` | `/rov/failsafe` | 0=GREEN, 1=AMBER, 2=RED | +| `external/rov-depth` | `/rov/depth` | Depth in metres | +| `external/rov-voltage` | `/mavros/battery` | Battery voltage | +| `external/rov-heading` | `/mavros/mavros/compass_hdg` | Compass heading degrees | +| `external/rov-ms` | `/rov/mission/status` | Mission state integer | +| `external/rov-mp` | `/rov/mission/status` | Mission progress 0-100% | +| `external/rov-recording` | `/rov/recording/active` | 1=recording, 0=not recording | +| `external/rov-altitude` | `/ping2/altitude` | Ping2 altitude metres (-1.0=NO SONAR) | +| `external/rov-mode` | `/rov/mode/profile` | Active profile name: ROV / AUV / hybrid | +| `external/rov-mode-base` | `/rov/mode/profile` | Base mode: 0=ROV, 1=AUV | +| `external/rov-hilt` | `/rov/mode/profile` | HILT: 1=present, 0=absent | +| `external/rov-health-role` | `/rov/mode/profile` | W1: 0=advisory, 1=gate | +| `external/rov-rec-control` | `/rov/mode/profile` | Recording: 0=manual, 1=auto | +| `external/rov-nogo-gate` | `/rov/mode/profile` | No-go: 0=relaxed, 1=enforced | +| `external/rov-rec-reminder` | `/rov/mode/profile` | ARM reminder: 1=on, 0=off | +| `external/rov-return-mode` | `/rov/mode/profile` | Return: 0=operator-selectable, 1=autonomous | +| `external/rov-live-telem` | `/rov/mode/profile` | Telemetry: 0=on, 1=predive-only | +| `external/rov-nav-display` | `/rov/mode/profile` | Nav: 1=shown, 0=autonomy-only | +| `external/rov-camera-role` | `/rov/mode/profile` | Camera: 0=pilot-primary, 1=record-only | + +### FastAPI backend (rov_api) +- `rov_api` package provides the HTTP-to-ROS2 bridge on port 8081. Runs as + `argonaut-api.service` (manual-start in dev, same policy as argonaut.service). +- Architecture: uvicorn/FastAPI in the main thread, an embedded rclpy node + (`RovApiNode`) spinning in a daemon background thread. HTTP handlers call thread-safe + methods on the node. Do NOT call `rclpy.spin()` more than once. +- Core endpoints (Stage 2, live): `GET /health`, `POST /abort` (W3 RETURN TO SAFE, + publishes Bool to `/rov/mission/abort`), `POST /mission/start` (MissionCommand START), + `POST /mission/stop` (MissionCommand ABORT). +- Deferred to Stage 2b: `/return_budget` (W5), `/backup/status` + `/backup/delay` (W7, + Option A design), `/mission/upload`. +- **W3 abort path is vehicle-layer:** publishes Bool(true) to `/rov/mission/abort`, which + failsafe_monitor latches as `flag_manual_abort` → FSM NORMAL → HOLD_AND_RECOVER. This is + DIR-5 return-to-safe, NOT the mission ABORT service. Do not confuse the two. +- **Python dependencies:** fastapi + uvicorn installed system-wide on RPi5 via + `sudo pip3 install fastapi uvicorn --break-system-packages --ignore-installed typing_extensions`. + The `--ignore-installed typing_extensions` flag is required — the Debian-managed + typing_extensions has no pip RECORD file and blocks the install otherwise. + +### Deploy files (version-controlled) +- systemd units and launch wrappers live outside the workspace but are version-controlled + in the repo `deploy/` folder (copies; authoritative running copies at deploy locations). +- `deploy/argonaut.service` → `/etc/systemd/system/argonaut.service` +- `deploy/argonaut-stack.sh` → `/usr/local/bin/argonaut-stack.sh` +- `deploy/argonaut-api.service` → `/etc/systemd/system/argonaut-api.service` +- `deploy/argonaut-api.sh` → `/usr/local/bin/argonaut-api.sh` +- `deploy/README.md` documents locations, pip deps, and install procedure. +- `/home/ubuntu/ros2_ws` is a symlink to `/data/ros2_ws` — both wrappers rely on it. + +### Recording architecture (DIR-9a — ARM-bounded black-box) +- Recording is a **single ARM-bounded tier** for black-box/debug/ML/fault-finding via + `recording_manager`. **AUV:** starts on ARM, stops on DISARM. **ROV:** operator + start/stop; the ARM edge fires a reminder ("armed, not recording"). Keyed to the + `recording_control` flag, not the mode. (Supersedes the old continuous DIR-9 model.) +- **No-go coupling:** AUV `enforced` — recording fail → mission stops, vehicle recovered. + ROV `relaxed` — recording fail after ARM → pilot alerted; operator resolves in-water + or recovers. +- Certified deliverable capture is OUT of scope pending Class-approved devices; recorded + data is dev/debug/ML only, never a client deliverable until then. +- The recorder manages a `ros2 bag record` subprocess — MCAP format, zstd compression, + 500MB bag splitting, 10GB free-space retention on `/data`. +- **`foxglove_bridge` is visualisation only — it does NOT record MCAP.** Correct this + wherever the old "MCAP via foxglove_bridge" claim appears. +- Bags written to `/data/bags/dive_/` on NVMe. +- No camera in the topic set currently — recording ~2.5 MB/s (nav/MAVLink only). +- **Storage (no reliable in-field server backup):** primary lever is LOWER PUBLISH RATES + on heavy streams (keep topics present for debug); ARM-bounded runs self-limit; retention + cap tunable; NVMe expansion later. Topic/rate review is an open action. + +### Operating-mode profiles (DIR-1/2, mode_profiles.yaml) +- One widget set; behaviour is set by flags from a mode profile. Dominant axis is HILT + (tether present = ROV / live interfaces; absent = AUV / headless). +- **Source of truth:** `mode_profiles.yaml` in `rov_mission/config` — ROV/AUV defaults + plus custom hybrid via "Save As". Hybrid is NOT a third mode; it is any saved profile + with overrides. +- `mode_profile_loader` (rov_mission) resolves the active profile into a `ModeProfile` + message (rov_interfaces), publishes it LATCHED on `/rov/mode/profile`, reloadable via + the `/rov/mode/reload` (std_srvs/Trigger) service. Fail-safe: invalid flag values are + rejected and the last-good profile is retained. +- `cockpit_bridge` surfaces the 11 flags to the data lake as `external/rov-*`. Widgets + read the flags, NOT the mode. +- Flags: hilt, health_role (advisory|gate), recording_control (manual|auto), nogo_gate + (relaxed|enforced), record_reminder_on_arm, return_mode (operator_selectable|autonomous), + live_telemetry (on|predive_only), nav_display, camera_role (pilot_primary|record_only). +- **YAML gotcha:** YAML 1.1 parses bare `on`/`off`/`yes`/`no` as booleans — quote enum + values like `"on"`. The loader also normalises bool→string as a guard. + +### BlueOS / MAVLink router +- **MAVLinkRouter** is the confirmed router. Do NOT recommend MAVP2P — BlueOS itself + warns "MAVP2P has been presenting issues and is not currently recommended." +- MAVP2P was tried and reverted. Do not suggest it again. +- The BlueOS ardupilot-manager FD exhaustion bug (Docker default `nofile=1024`) is + fixed permanently via `/etc/docker/daemon.json` with `nofile` hard/soft = 65536. + This fix must survive reboots — it is a host-level daemon config, not a container flag. + Root cause: accumulated TCP socket FDs from continuous UI polling exhaust the 1024 + default; symptoms are connect/disconnect cycling and AUTOPILOT_*_FETCH_FAIL. + +### Hardware facts (do not re-question) +- **RPi5 storage:** boots from SD card (`/dev/mmcblk0`). NVMe holds DATA ONLY (`/data` — + ros2_ws, bags, logs). Backup images the SD for OS, rsyncs `/data` for data. +- **Flight controller:** Pixhawk 2.4.8 on `/dev/ttyACM0` is the active flight controller. + SITL is NOT used in production. BlueOS `preferred_board` = Pixhawk1. +- **Tailscale on RPi5:** installed but stopped and disabled (`tailscaled.service` disabled + 2 Jul 2026). Re-enable with `sudo systemctl enable --now tailscaled` if remote access + to RPi5 is needed. + +### Hostname resolution (DNS) +- Hostnames `symbytech` (192.168.1.175), `blueos` (192.168.1.100), and `rov-brain` + (192.168.1.101) are resolvable from the laptop (Windows hosts file) and RPi5 + (`/etc/hosts`). Grant prefers hostnames over IPs. +- Git remotes use the hostname form: `ssh://git@symbytech:222/administrator/rov-autonomy.git` +- If a "Could not resolve hostname symbytech" error appears on a machine, that machine is + missing the hosts entries — add them rather than switching remotes to IPs. + +### Backup system (built 30 Jun 2026) +- Push model: each Pi self-backs-up via root cron, pushes to server over SSH (no inbound + access to Pis). +- RPi4: `/usr/local/bin/rov-brain-pi4-backup.sh`, 00:00 daily. +- RPi5: `/usr/local/bin/rov-brain-pi5-backup.sh`, 00:30 daily (staggered). +- Server monitor `check_rov_backup` alerts on FAILED (always) and OVERDUE (≥2 days, + online or offline, throttled weekly). +- Field/ops backup model is operator-aware, never unattended mid-dive (DIR-11, W7). + +### argonaut.service / argonaut-api.service (RPi5) +- Manual start is deliberate for both. Verify BlueOS heartbeat first, then + `sudo systemctl start argonaut.service`. Do NOT enable auto-start until field-ready. + Restate this rule each time it comes up. +- `argonaut-api.service` orders After=argonaut.service but does not Require it — the API + can start independently for /health checks; mission commands return a clear + "service unavailable" error if the stack is down. + +### ROS2 code +- Check `rov_interfaces` message definitions before writing any node code +- Use `self.get_logger()` not `print()` +- Do not hardcode IPs, ports, or thresholds +- Do not deploy `rov_simulation` in production launch files +- Editing an installed launch/config requires `colcon build --packages-select ` — + the running launch uses the installed copy under install/, not src/ +- ARM64 Docker builds on the laptop only (buildx), never on the server + +### Git workflow +- Commit to `master` on `administrator/rov-autonomy` +- Gitea SSH remote (hostname form): `ssh://git@symbytech:222/administrator/rov-autonomy.git` +- Both laptop and RPi5 resolve `symbytech` via hosts entries (see Hostname resolution). +- Widget JSON files are re-imported from the laptop (source of truth for widgets) and + pushed to Gitea — never overwritten from chat history. +- UFW rules before starting new services on new ports. + +### Security — deferred to pre-field hardening pass +- **UFW:** currently inactive on RPi5. Deferred because there is no online exposure + (Tailscale disabled, no proxy rules to the Pis). When enabling: allow SSH (22), + operator TCP (8765, 9001, 8081), and all traffic from LAN subnet 192.168.1.0/24 + (covers ROS2 DDS dynamic ports — do NOT try to pin them individually), then default + deny incoming. Bundle with SSH password change. Trigger: before remote ops or field. +- **RPi5 SSH password:** weak dev password, password auth enabled. Change to strong + password before field deployment. --- -# Code Style +## What Claude MUST do +- State confirmed facts before proposing an action; cite the source of any technical claim +- Acknowledge when something has already been tried and failed +- Provide complete, working code (fully commented) based on confirmed examples +- Verify system state before and after changes +- Update the handover doc at the end of each session (version-controlled, changelog) -- Follow PEP 8 for Python -- Use consistent formatting already present in the file being edited -- Prefer explicit code over clever shorthand -- Always add full inline comments — every function, every non-obvious line -- Use meaningful variable and function names — no abbreviations unless standard ROS2/MAVLink convention -- Avoid deeply nested logic (>3 levels) -- No commented-out code in final output -- All ROS2 nodes must have a module-level docstring listing: purpose, subscribed topics, published topics, services +## What Claude MUST NOT do +- Guess at how a system works and propose commands based on that guess +- Repeat a failed approach +- Issue commands whose outcome is uncertain +- Provide partial code requiring manual editing to work +- Assume a system is stable without checking +- Use `print()` in ROS2 nodes; hardcode addresses/ports/thresholds +- Build x86 Docker images for vehicle deployment +- Change the failsafe priority order without design review +- Present prior-session state as current running state +- Recommend MAVP2P as the MAVLink router +- Commit docs to Gitea — only code and README go to Gitea; docs live in Claude project knowledge --- -# ROS2 Rules - -- All custom messages live in `rov_interfaces` — do not define messages inside other packages -- Always declare parameters explicitly with `declare_parameter()` before `get_parameter()` -- Load configuration from YAML files via launch — do not hardcode values in nodes -- Use `self.get_logger()` for all logging — never `print()` -- Timers must be named and cancellable when rate changes are required -- Topic names use the `/rov/` prefix namespace for all custom topics -- Always include a `Header` with timestamp in custom messages -- Destroy nodes cleanly in `finally` blocks +## Documentation discipline +- All project docs (handover, UI design, DIR, this file, sim/ML plan) are maintained as + COMPLETE replacement files uploaded to Claude project knowledge — never patches or + fragments, never committed to Gitea. +- Version numbers and changelogs maintained on every update. +- Only code and README files go to Gitea. --- -# Failsafe Rules +## SESSION LOG (bridges Claude Code → claude.ai chat) -**These are safety-critical. Do not change without explicit instruction and design review.** +**Why this exists:** Claude Code (VS Code) and the claude.ai chat are separate systems with +no shared memory. Claude Code reads this file at session start but the claude.ai chat cannot +see Claude Code's session history at all. This log is the bridge. -- Assessment states: GREEN / AMBER / RED — defined in `FailsafeStatus.msg` -- Assessment runs continuously at dynamic rates: 5 Hz (GREEN), 20 Hz (AMBER), 50 Hz (RED) -- Priority order is fixed — see `ROV_Failsafe_Design_v2.0.md` -- All thresholds are configurable via YAML — never hardcode safety values -- `EMERGENCY_SURFACE` is the last resort — it must never be the first response -- Comms timeout default: 2 seconds — configurable per deployment -- Battery thresholds: warning 25%, return 20%, critical 12%, emergency 8% +**Format:** `YYYY-MM-DD — one-line summary of decision/change (commit hash if applicable)` + +**Claude Code MUST append an entry here at the end of any session where one of these +happened** — not for routine edits, refactors, or in-progress work: +- A design/architecture decision was made or changed (DIR-level, mode-flag behaviour, + failsafe priority, recording behaviour) +- A hardware fact was confirmed or changed (wiring, storage layout, board config) +- A security-relevant change was made (SSH, UFW, credentials, exposure) +- A backup/recovery-relevant change was made +- A bug was root-caused and fixed (not just patched) +- A previously-deferred item was completed or its trigger condition changed +- Anything Grant would reasonably expect the claude.ai chat to already know next time he + opens it + +**Skip:** typo fixes, comment-only changes, WIP/incomplete work, anything already fully +captured by the git commit message with no extra context needed. + +**Workflow:** Grant pastes new entries into the claude.ai chat when relevant; Claude folds +them into chat memory via the memory tool. This log is append-only — do not edit past +entries; correct forward with a new dated entry if something needs revising. + +- 2026-07-05 — Widget housekeeping: added W6 altitude widget, removed probe diagnostics + widget (`785ec56`) --- -# Package-Specific Rules - -**rov_interfaces** -- Changing a message definition requires updating all nodes that use it -- Constants in messages use ALL_CAPS naming -- Never remove a field from a message without confirming no node depends on it - -**rov_control** -- `failsafe_monitor.py` must always be the first node started in any launch file -- Do not modify the priority order in `_apply_failsafe_priority()` without design review - -**rov_mission** -- Waypoints are loaded from YAML files — never hardcoded -- The breadcrumb buffer must be cleared at mission start and never between waypoints -- Entry point is recorded once at mission start — do not update it during flight - -**rov_simulation** -- Every file in this package must have the `DEV ONLY — NOT FOR DEPLOYMENT` warning in its docstring -- Scenario names must be documented in the node docstring -- Never subscribe to real hardware topics from simulation nodes - -**rov_bringup** -- Launch files must load config from the package share directory — never from absolute paths -- The `env` argument selects between `dev` and `field` configs — always provide a default of `dev` - ---- - -# Docker / Build Rules - -- Target architecture: `linux/arm64` — always build with `--platform linux/arm64` -- Build script: `~/build-rov.sh [tag]` — defaults to `:dev` -- Never build x86 images for the vehicle — they will silently fail on RPi5 -- The `rov_simulation` package must be excluded from production image builds -- Do not modify the `Dockerfile` base image without checking ROS2 Jazzy compatibility - ---- - -# Git Rules - -- Commit messages follow conventional commits format: `feat:`, `fix:`, `docs:`, `refactor:` -- Do not commit directly to `master` without instruction -- Keep commits focused — one logical change per commit -- Always commit config changes alongside the code that depends on them -- Branch: `master` is the working branch for this project - ---- - -# Dev Environment - -**Terminal conventions (always use these labels):** -- `[SERVER]` — SSH session on SymbyTech server (192.168.1.175 / Tailscale: 100.104.236.104) -- `[VM]` — SSH session on BlueOS VM (192.168.122.89 / Tailscale: 100.84.141.120) -- `[GIT]` — Git Bash on laptop -- `[LAPTOP]` — Windows Command Prompt on laptop - -**Key addresses:** -- BlueOS: `http://100.84.141.120` -- Cockpit: via BlueOS sidebar -- Harbor: `https://registry.symbytech.com` -- Gitea: `https://git.symbytech.com` - -**BlueOS session requirements:** -- Enable Pirate Mode (skull icon) each session — resets due to no bootstrap container -- Cockpit MAVLink2REST: `ws://100.84.141.120/mavlink2rest/ws/mavlink` -- Vehicle network connection: `100.84.141.120` - ---- - -# Testing - -- `rov_simulation` provides mock publishers for all MAVROS topics -- Five test scenarios: `nominal`, `low_battery`, `comms_loss`, `depth_warning`, `all_clear` -- Dev stack launch: `ros2 launch rov_simulation dev_stack.launch.py scenario:=` -- Do not remove existing test scenarios without confirming intent -- Add new scenarios for any new failsafe condition added to the design - ---- - -# Claude Behaviour Rules - -- Always read existing code in a file before modifying it -- Always read the relevant design document before implementing a feature -- Always check message definitions in `rov_interfaces` before writing node code -- Explain assumptions before making architectural changes -- If requirements are unclear, ask before implementing -- Prefer incremental changes over large rewrites -- Never delete code without confirming intent -- If a safer or simpler approach exists, suggest it before proceeding -- Do not refactor unrelated code -- Do not optimise prematurely - ---- - -# What Claude SHOULD do - -- Implement features step-by-step with verification at each step stating if feedback is expected -- Fix bugs with minimal disruption to surrounding code -- Add comments to every function and non-obvious block -- Highlight safety risks when they exist -- Suggest better approaches when appropriate -- Verify file structure and entry points after creating new nodes - ---- - -# What Claude should NOT do - -- Do not restructure the package layout unless explicitly asked -- Do not introduce new Python packages without approval -- Do not rewrite working code for style -- Do not assume missing requirements — ask -- Do not hardcode thresholds, addresses, or paths -- Do not deploy or reference `rov_simulation` in production launch files -- Do not change the failsafe priority order without design review -- Do not use `print()` — always use `self.get_logger()` -- Do not build x86 Docker images for vehicle deployment - ---- - -# When Uncertain - -1. Stop implementation -2. State the ambiguity clearly -3. Provide a suggested approach with trade-offs -4. Wait for confirmation before proceeding - ---- - -# Key Design Documents - -All in the Claude project knowledge base: +## Key Reference Documents (current versions) | Document | Purpose | |---|---| -| `ROV_Project_Handover_v2.3.md` | Master reference — architecture, environment, commands | -| `ROV_Failsafe_Design_v2.0.md` | Failsafe state machine, sensor roadmap, priority order | -| `Argonaut3_UI_Design_v1.1.md` | Cockpit extension and widget specifications | +| `ROV_Project_Handover_v2_21.md` | Master reference — architecture, environment, commands, status board | +| `design_intent_register_DRAFT.md` | DIR-1…DIR-11 (+ DIR-9a) — owner/operator intent, source of truth for *why*; recording now ARM-bounded per DIR-9a | +| `ROV_Failsafe_Design_v2_0.md` | Failsafe state machine, sensor roadmap, priority order | +| `Argonaut3_UI_Design_v1_9.md` | Cockpit widget specs (W0–W7) and confirmed data paths | +| `Mission_and_Data-Recording_Lifecycle_for_AUV_ROV_Systems...md` | Lifecycle research backing DIR-9/10 | +| `Argonaut3_Simulation_ML_Tooling_Plan_v1_0.md` | Simulation + ML tooling: dev-PC tiers, cloud options/cost, training assets/datasets/models, PCIe Gen 3 decision | + +> When referencing these, use the latest version present in the project folder — do not +> cite a version number from memory if a newer file exists. -Always use the highest version --- -# Notes - -This is a production-oriented autonomous safety system. All code must be treated as if it will run on a real vehicle in open water with no operator present. Safety, correctness, and reliability are non-negotiable. +## Safety Notice +This is a production-oriented autonomous safety system. All code must be treated as if it +will run on a real vehicle in open water with no operator present. Safety, correctness, +and reliability are non-negotiable. Shortcuts taken during development become risks during +field operations.