# Design Intent Register — Argonaut 3 **Version:** 1.5 **Date:** 14 July 2026 **File:** `docs/design_intent_register.md` (repo-tracked, no version number in filename) **Purpose of this register:** Capture operator/owner *intent* — what each behaviour MEANS and MUST/MUST NOT do — separately from mechanism (topics, code). Mechanism is recorded elsewhere. This register is the source of truth for *why*, against which any implementation is validated. Every entry dated and attributed. --- ## Changelog | Version | Date | Change | |---|---|---| | 1.5 | 14 Jul 2026 | **Two new DIRs — documentation-only pass, no code changed.** **DIR-13 — widget-to-hardware ownership map:** records which subsystem (RPi4 gateway vs RPi5 autonomy brain) each widget reflects, as owner-stated intent. W1 is a two-stage health gate — FC heartbeat on RPi4 MUST pass first (already implemented, `86b2728`, 11 Jul), then RPi5 autonomy-stack self-health (not yet built); only when both pass is W1 GREEN. W5 reflects the RPi4-connected battery. W2/W3/W4/W6/W8 reflect the RPi5 stack; W6 altitude is deliberately kept RPi5-direct, consistent with the standalone-autonomy principle (BlueOS/Cockpit integration is the only current external dependency). W7 specced, not built. Cross-references DIR-12. **DIR-14 — depth is a dual-source, operator-selectable input:** depth may come from an RPi4 sensor (via the FC) or an RPi5-direct sensor; the system should support selecting one, the other, or a blend, chosen at mission setup (W4) and carried in the resolved mode profile like other settings. Redundancy plus operator choice; consistent with the same standalone-autonomy principle as DIR-13/W6. Design-captured intent for a future build, not yet specified in detail. | | 1.4 | 13 Jul 2026 | **CORRECTION: DIR-7 "in-mission recovery is mode-dependent" addendum was inverted — fixed.** The 11 Jul wording had AUV gate mode commit to recovery ON CONDITION-CLEAR; that produced a contradictory GREEN-while-in-`RETURN_TO_SAFE` state observed live. Corrected model: GREEN is unconditionally a working state; committed recovery is triggered by fault PERSISTENCE or RECURRENCE, never by clearing. Records a three-tier fault model (uncontrollable/out-of-scope for the FSM; transient/self-resetting with a raw failure-count trigger, deliberately no time window; hard/persistent, a RED that doesn't clear) with all thresholds configuration-driven via the resolved mode profile, same as `health_role`. Records what survives (health_role mode-awareness from `2a3e577`; the safe-zone-reached arrival-exit mechanism from `bf815cc`, unchanged in role) vs what's retired (the condition-clear entry logic in `2a3e577`, which `bf815cc` built its exit on top of) — pending next-session rework into the count-based model. **New Parked Design Item:** adaptive restart-timing (monitor own restore count/duration, weigh future attempts against observed history rather than a fixed time) — depends on the count-based retry machinery above existing first; design-captured, not build-specified. | | 1.3 | 13 Jul 2026 | **New Parked Design Item:** mode-aware safe-zone-reached arrival event (relates to the DIR-7 "in-mission recovery is mode-dependent" addendum) — the permanent `/rov/nav/safe_zone_reached` interface, mode-aware/sensor-derived arrival judgement (GPS at surface + EKF/dead-reckoning underwater), GPS recorded as first-class across mission types (not a hull/jacket-specific surface concern), gate-only scope, and the temporary W1-button bench-scaffolding publisher pending navigation. Implemented same day in `failsafe_monitor` (`bf815cc`) — see `docs/handover.md` §15f for the fix narrative; this entry records the design intent, not the commit detail. DIR-7 addendum's Implementation note updated: the mode-dependent recovery mechanism is no longer mode-blind (`2a3e577`, 13 Jul 2026). | | 1.2 | 11 Jul 2026 | **DIR-7's FC-connectivity MUST — RESOLVED**, four commits 11 Jul 2026 (full detail in `docs/handover.md` Changelog); open-flag callout updated accordingly. **DIR-7 gains two addenda:** in-mission recovery is mode-dependent (AUV commits to recovery on condition-clear, does not auto-resume; ROV holds and hands the continue-or-recover decision to the operator); and in-mission AMBER runtime-response (AMBER means action-required, not just informational, once a mission is underway — response branches by mode, AUV's autonomous curtailment logic left unspecified pending further design). **New "Parked Design Items" section** — auto-recovery (failsafe_monitor should attempt to re-establish the FC link itself before escalating) and a dedicated `string cause` field in `FailsafeStatus.msg` (replacing the `cockpit_bridge` message-substring shortcut) — both tracked as open implementation gaps against existing DIR-7/12 intent, not new decisions. Filename de-versioned as part of the 11 Jul doc restructure — this file moved into the repo `docs/` folder. | | 1.1 | 9 Jul 2026 | **DIR-1 corrected** — the *tether/HILT link*, not the power source, determines operating mode. A tethered vehicle may run on battery or topside supply. **DIR-7 expanded** — AUV `gate` vs ROV `advisory` health semantics; and a MUST that health assessment include flight-controller connectivity (a monitor with no FC input must never report GREEN). **DIR-9 superseded by DIR-9a** — recording is a single ARM-bounded black-box tier, not continuous-from-boot. **DIR-12 added** — vehicle health is distinct from autonomy health. | | 1.0 | Jun 2026 | Initial register. | > ⚠ **Known implementation drift (updated 13 Jul 2026):** `recording_manager.py` still implements > the superseded DIR-9 (continuous-from-boot) model, NOT the governing DIR-9a — **still open.** > `failsafe_monitor`'s DIR-7 FC-connectivity MUST is **resolved** (11 Jul 2026, see DIR-7 below). > The DIR-7 "in-mission recovery is mode-dependent" addendum's **core trigger logic was corrected > 13 Jul 2026** — the previous condition-clear-commits-to-recovery model was inverted and wrong > (it produced a contradictory GREEN-while-in-`RETURN_TO_SAFE` state observed live); see the > addendum below for the corrected count-based tier model. **`failsafe_monitor`'s current code > (`2a3e577`) still implements the RETIRED, known-wrong condition-clear entry logic** — this is > now a known implementation gap needing rework, not merely an unimplemented addendum, pending a > dedicated next session. The safe-zone-reached arrival EXIT mechanism (`bf815cc`) remains > correct and unaffected by this correction — only entry into committed recovery was wrong. The > AMBER runtime-response addendum, auto-recovery, the dedicated `string cause` field, and the new > adaptive restart-timing item all remain **intent recorded, not implemented**. DIR-12's broader > vehicle-health framing remains open beyond the FC-link piece (FD-headroom check on > `ardupilot_manager` not built). --- ## DIR-1 — Platform is a single dual-capability vehicle (AUV + ROV) **Source:** Grant, June 2026 session. **Intent:** One physical platform that is *both* an AUV and an ROV. It is not two vehicles or three abstract modes. The **tether / human-in-the-loop (HILT) link determines the operating mode**: - **No HILT link (untethered)** → operates as a pure **AUV**: fully autonomous, NO human in the loop. Mission plan + sensor data + parameter-governed rules drive everything, including aborts. - **HILT link present (tethered)** → operates as an **ROV with AUV abilities (HILT)**: the same autonomy stack runs the mission identically, but a human operator is able to intervene. > **CORRECTED 9 Jul 2026.** This entry previously stated that the *power source* determines the > operating mode. That is WRONG. **Power source and operating mode are independent.** A tethered > vehicle may run on internal battery or on topside supply; either way it is an ROV because the > HILT link is present. The dominant axis is the link, not the volts. **Must:** Treat autonomy as one shared path used in both modes. **Must:** Derive mode from HILT-link presence, never from power source. **Must not:** Implement two separate autonomy/abort flows for AUV vs ROV. --- ## DIR-2 — HILT is an override channel, not a confirmation gate **Source:** Grant, June 2026 session (explicit clarification). **Intent:** In BOTH modes, the autonomy runs the same rules and **acts automatically by default**. Normal operations are identical in AUV and ROV mode. The ONLY difference in tethered/ROV mode is that the operator **can intervene when/as required** — override a rule's action, or continue manually under conditions the autonomy would otherwise abort on (an experienced pilot may safely continue where rules alone would not). **Must:** - Run the autonomous rule-driven path always, in both modes. - Provide an intervention/override channel that is active only when tethered. - Degrade safely: if the operator does nothing, the vehicle behaves exactly as an AUV. **Must not:** - Block or pause autonomous action waiting for human confirmation. - Require operator input for the vehicle to act. Intervention is optional, never a precondition. --- ## DIR-3 — Mission is a process (aerial-drone model) **Source:** Grant, multiple sessions; consolidated June 2026. **Intent:** The mission follows the same lifecycle as an aerial survey drone: 1. Mission is **created or uploaded to the ROV beforehand** — a process, not a button-time action. 2. Pilot **manually launches** and flies the ROV to a **safe place**. 3. Pilot **starts the mission** → ROV departs, follows the plan, records data + video/stills as instructed. 4. **Normal end:** ROV **autonomously returns to a designated safe place**; pilot takes over for recovery. **"Safe place / safe zone":** Operator-designated location, closest to the mission start, where the ROV can safely be recovered or hold. Used both as the normal return point and as the abort return point. (Drone "home" equivalent.) --- ## DIR-4 — Mission Start / Stop (mission-layer; paired function) **Source:** Grant, June 2026 session. **REVISED to align with AUV/ROV lifecycle research (see DIR-9).** **Intent:** Control of the *mission* (the survey), distinct from any vehicle-safety action. - **Start** — "go do the inspection." Begins mission-plan execution. - **Stop** — "inspection is done, or I'm calling it off." Ends mission execution. **RECORDING — revised per research (DIR-9):** Mission Start/Stop does NOT start/stop the recorder itself. The recorder runs continuously and independently (DIR-9). Mission Start/Stop controls *what is sampled* and *splits the MCAP bag* on a mission-phase boundary, per the active record profile (DIR-10). This avoids the "mission ran but nothing recorded" failure mode — the single most important reason mature systems (ArduPilot, MBARI LRAUV, QGroundControl, MOOS-IvP) do NOT gate the recorder on mission state. **Must:** - On Start: begin mission execution; split the bag to mark mission start; apply the mission's record profile (which streams sample). - On Stop: end mission execution; split the bag to mark mission end. - Treat "recorder not active" as a no-go for Start (DIR-9). **Must not:** - Command any vehicle movement. Start/Stop is mission-layer only. - Stop or kill the recorder process on mission Stop — the recorder keeps running continuously. **UI note:** Start/Stop is a command (mission already created/uploaded per DIR-3). *What to record* is selected at plan time via the record profile (DIR-10), with runtime override available. --- ## DIR-5 — ROV Abort / Return-to-Safe (vehicle-layer) **Source:** Grant, June 2026 session. **NOTE: supersedes the earlier mislabelled "manual abort" intent.** **Intent:** A *vehicle safety* action, NOT merely a recording stop. Triggered when conditions exceed designated levels (power and others — see failsafe spec thresholds). Behaviour depends on mode per DIR-1/DIR-2: - **AUV mode (untethered):** rule fires → vehicle automatically stops recording and returns to the closest safe place. No human. - **ROV/HILT mode (tethered):** same rule fires and would act as in AUV mode, BUT the operator can intervene — either accept (let it return to safe) or override (continue, autonomously per mission or manually). **Recording — revised per research (DIR-9):** On return-to-safe, the mission ends so *mission sampling* stops, but the recorder keeps running continuously through the transit and recovery (matches every mature system: keep recording through the return phase, split the bag on the phase boundary). The earlier intent "recording stops on return-to-safe" is refined: *mission-driven high-rate sampling* stops; the *always-on core recording* continues. Rationale: the return transit is itself valuable data, and stopping the recorder mid-event risks losing the record of why the abort happened. **Must:** - Use the DP-state (GREEN/AMBER/RED) assessment logic to drive the action. - Stop all recording when returning to safe. - Return the vehicle to the *closest* designated safe place. - In tethered mode, expose alert + override capability to the operator. **Must not:** Be labelled simply "abort" in a way that implies an emergency hard-stop. It is a return-to-safe, not an emergency surface. **Open / staged:** HILT alert-accept-reject-override flow is multi-stage work (see staging below). Tethered-first development is a potential machine-learning opportunity. --- ## DIR-5a — Abort is mission-bounded; outside a mission the vehicle is manual ROV **Source:** Grant, June 2026 session (correction/refinement). **Intent:** The autonomy, rules, and abort logic (DIR-2, DIR-5) apply **only while a mission plan is executing**. - **No mission running** → the vehicle is **entirely manually controlled by the operator**. It operates as a plain ROV. No autonomy drives it. There is nothing to abort. - **Abort/return-to-safe only exists within a mission.** It is a mission-context action, bounded by mission start and mission end. **Lifecycle:** 1. Manual control → pilot launches and flies to safe place (manual). 2. Mission starts → autonomy active, rules apply, abort available. 3. Mission ends (normal return-to-safe, or abort) → back to manual control for recovery. **Must:** Only arm autonomy/abort logic while a mission is executing. **Must not:** Allow abort or autonomous action when no mission is running. --- ## DIR-5b — Operator override continues the mission (alerts are early, parameter-driven) **Source:** Grant, June 2026 session. **Intent:** When the operator intervenes during a mission (tethered/ROV mode), the intervention **continues** the mission — it does NOT terminate or pause it. The mission context stays live throughout. **Design goal:** Alerts should fire **early enough** that the operator can act *before* any pause or abort becomes necessary. This is **parameter-driven** — the alert thresholds (the "designated levels" in DIR-5) must give a wide enough margin for intervention ahead of a forced abort. **Consequence:** Threshold tuning is critical. The HILT advantage depends entirely on the alert margin being wide enough to intervene before the condition forces return-to-safe. Ties directly to the config UI (staging Stage 4). **Must:** Keep the mission running through operator intervention. **Must not:** Drop to manual control or pause the plan as a side-effect of intervention. --- ## DIR-6 — Emergency Surface (SHELVED — flagged for later) **Source:** Grant, failsafe design session + June 2026. **Intent:** Last-resort hard stop. Surfaces the vehicle regardless of surroundings. Highest risk action; must never be a first response. **Status:** SHELVED. Not in current scope. To be reviewed later. May potentially be combined with DIR-5 return-to-safe at review time (Grant: "we could combine point 3 and 4"). --- ## DIR-7 — DP lights linked to mission capability **Source:** Grant, failsafe design session. **Expanded 9 Jul 2026.** **Intent:** The GREEN/AMBER/RED DP-style states (W1) show the ROV's *ability to conduct the mission*. They are explicitly linked to mission capability. Mission start/stop and ROV abort are separate functions, but the DP state informs the abort decision (e.g. AMBER conditions → operator would stop mission and return to safe). **Mode-dependent role (`health_role` flag):** - **ROV (`advisory`)** — display only. The pilot sees the state and decides. A HILT operator is present. - **AUV (`gate`)** — W1 is the **pre-dive GO/NO-GO gate**. RED blocks mission start. There is no operator once submerged, so this is the last human-visible decision point. **Semantics (AUV, parameter-driven):** GREEN = within designated levels; AMBER = approaching a designated level; RED = terminate / do not start. **MUST — health assessment includes the vehicle, not just the autonomy stack:** The assessment MUST incorporate **flight-controller connectivity and heartbeat age**. A dead or unreachable FC is a RED condition. This is not optional: in AUV mode W1 is a gate, and a gate that cannot see the flight controller is not a gate. **MUST — absence of data is not health:** A monitor with no input MUST NOT report GREEN. "No data" and "good data" are different states and must be distinguishable in both the assessment and the display. **MUST — the state must carry its cause:** W1's status line carries cause text (e.g. `"Vehicle Disconnected"`, `"Heartbeat Lost"`, `"No Board Running"`, `"Systems nominal"`), not a bare colour. An operator must be able to act on the state without opening another tool. > ✅ **Resolved 11 Jul 2026** (was open, safety-critical, 9 Jul 2026): `failsafe_monitor` now > drives W1 RED unconditionally on FC comms loss, with a `fcu_ever_connected` latch closing the > startup-window GREEN gap, and carries cause text on `FailsafeStatus.message` per the MUST > above. Four commits — full narrative in `docs/handover.md` Changelog, 11 Jul entry. This DIR > entry is not the place for commit-level detail; it records that the MUST is now satisfied. --- ### DIR-7 addendum — In-mission recovery is mode-dependent (11 Jul 2026, **CORRECTED 13 Jul 2026**) **Source:** Grant, 11 Jul 2026 session. Extends the advisory-vs-gate framing above from the pre-dive gate to the in-mission runtime case. **Core trigger logic corrected 13 Jul 2026 (Grant) — see callout immediately below.** > ⚠ **CORRECTED 13 Jul 2026 (Grant).** The original text of this addendum stated that AUV gate > mode **commits to the recovery action ON CONDITION-CLEAR.** That is inverted and wrong. It > produced a contradictory state observed live: the failsafe assessment reporting GREEN (the > fault cleared) while the FSM sat in `RETURN_TO_SAFE` (committed recovery) — a "green light, > still returning to safe" state that should not be possible. **The corrected intent:** GREEN is > unconditionally a **working state** — a fault that clears returns the vehicle to GREEN and the > mission continues or resumes; a cleared condition must **never** trigger or commit a recovery. > Committed recovery is triggered by a fault **persisting or recurring**, never by it clearing. > The rewrite below is the corrected model, replacing the retired condition-clear wording — see > "What survives / what is retired" near the end of this addendum for the implementation impact. **Intent (corrected 13 Jul 2026):** Recovery response is governed by a **three-tier fault model**, not by whether a condition has cleared: 1. **Uncontrollable tier — out of scope for the FSM.** Loss of power, or any failure that disables the safety logic itself, cannot be governed by a parameter inside the very system that has just been disabled — there is no FSM response to "the thing running the FSM is gone." This tier is adjacent to, and does not duplicate, the shelved DIR-6 Emergency Surface last-resort concern above; it is noted here only so it is not mistaken for a gap in tiers 2/3 below. 2. **Transient / self-resetting tier.** E.g. a comms blip, or a critical-sensor re-sync that can restore on its own. The system **attempts to restore**; on success, it returns to **GREEN** and the mission **continues or resumes** — a successful restore is not itself a reason to recover. Each failure **increments a count**. Only once the failure count **exceeds a configured acceptable number** does the FSM commit to `RETURN_TO_SAFE`. The count is a **raw count of failures for the mission** — deliberately **no time window, no fixed duration** — because time-window/duration-based logic will not survive changing startup periods and mission lengths. (Time/duration-aware sophistication is parked separately — see "Adaptive restart-timing" in Parked Design Items below — and depends on this raw-count mechanism existing first.) 3. **Hard / persistent tier.** A RED condition that does **not** clear. Commits to `RETURN_TO_SAFE` immediately, without waiting on a count — there is nothing to count against; the fault is already known to be hard. **Mode-dependent role, same shape as the original addendum, now operating on the tier model above rather than on condition-clear:** - **AUV (`gate`)** — commits to `RETURN_TO_SAFE` when a fault crosses into tier 3 (hard/persistent) or tier 2's failure count is exceeded — **never** merely because a condition cleared. Once committed, recovery runs to completion (the vehicle returns to / holds at the designated safe place per DIR-3); resuming the survey itself is a fresh, deliberate mission start (DIR-10), never an automatic side-effect of anything clearing. There is no operator to ask, so the vehicle must not guess that a transient success means "carry on as if nothing happened" — tier 2 already handles that correctly, by returning to GREEN and resuming on a *successful restore*, not on the fault merely being absent this instant. - **ROV (`advisory`)** — holds during an active AMBER/RED condition and hands the continue-or-recover decision to the operator. The operator decides whether to accept recovery or override and continue, per DIR-5's existing tethered intervention model. Matches DIR-5b: an operator override continues the mission; it does not force a recovery the operator didn't ask for. **All thresholds are configuration-driven, not hardcoded:** the acceptable failure count (tier 2), and the classification of which specific faults are transient (tier 2) versus hard (tier 3), are set in the setup wizard and read from the resolved mode profile the same way `health_role` is — never hardcoded in `failsafe_monitor`. **Must:** - Derive the post-recovery behaviour from `health_role` (`gate`/`advisory`), never assume the same generic response is correct for both modes. - Trigger committed recovery on fault **persistence or recurrence** (tier 2 count exceeded, or tier 3 hard fault) — **never** on condition-clear. - On a successful transient restore (tier 2), return to GREEN and continue/resume the mission — a successful restore is not a reason to recover. - AUV: treat mission resumption as a separate, deliberate action (DIR-10), never implicit in a restore or in reaching NORMAL. - ROV: surface the continue-or-recover choice explicitly; do not auto-decide on the operator's behalf. - Keep all thresholds (acceptable failure count, transient-vs-hard fault classification) configuration-driven via the mode profile, never hardcoded. **Must not:** - Commit to, or remain committed to, recovery because a condition cleared. A cleared condition is evidence the vehicle is fine, not evidence it needs recovering. - Use a time window or fixed duration to decide whether a fault is "still happening" for the purpose of this trigger — use the raw failure count (tier 2). Time/duration awareness is a separate, later piece of sophistication (see "Adaptive restart-timing" Parked Design Item). **What survives from the 11 Jul / 13 Jul implementation work, and what is retired (13 Jul 2026):** - **Survives, correct:** `failsafe_monitor` subscribing to the resolved mode profile and reading `health_role` (commit `2a3e577`'s mode-awareness mechanism) — this is the right way to know which branch above applies, unchanged by this correction. - **Survives, correct:** the safe-zone-reached arrival event and its permanent `/rov/nav/safe_zone_reached` topic interface (commit `bf815cc`) — this remains the correct means by which a **committed** `RETURN_TO_SAFE` recovery runs to completion and exits back to `NORMAL` on arrival. Its role is **unchanged** by this correction: it completes a committed recovery. Only the trigger for **entering** committed recovery was wrong — how a committed recovery **exits**, once genuinely entered, is untouched and still correct. - **Retired, known-wrong, pending rework:** the **condition-clear-commits-to-recovery entry logic** — specifically, `2a3e577`'s gate-mode `HOLD_AND_RECOVER` → `RETURN_TO_SAFE` transition on condition-clear (the `health_role == HEALTH_GATE` branch in `failsafe_monitor._apply_failsafe_priority`'s "all clear" block), which `bf815cc` then built its (correct) arrival exit on top of. The entry logic is now known-wrong per the correction above and will be reworked next session into the tier-2 count-based persistence model described here. Until reworked, treat that entry code path as implementing the retired (wrong) intent, not this corrected one. > **Status:** Corrected 13 Jul 2026 (Grant). Design intent corrected; implementation rework > (count-based tier-2 persistence trigger, config-driven thresholds) is a next-session task — > `failsafe_monitor`'s current condition-clear entry logic is known-wrong in the meantime. --- ### DIR-7 addendum — AMBER runtime-response, in-mission (drafted 11 Jul 2026) **Source:** Grant, 11 Jul 2026 session. **Intent:** The pre-dive semantics above ("AMBER = approaching a designated level") describe a gate check before a mission starts. **In-mission, AMBER means something more actionable: the vehicle CAN still operate, but SHOULD NOT continue as currently planned, and action IS required.** It is not merely informational once a mission is underway — it is a call to do something, not just a status light. Response branches by mode: - **AUV (`gate`)** — no operator is present to hand the "action required" decision to. The autonomy stack must itself decide the appropriate curtailment (continue the current leg at reduced confidence vs. curtail and return to safe). AMBER does not by itself force an immediate hard return the way RED does. **Exact decision logic is not yet specified** — this addendum records the intent (AMBER demands a response, not just a display), not the algorithm. Left as design work, not to be inferred or invented ahead of a dedicated session. - **ROV (`advisory`)** — surfaces to the operator as "action required" per DIR-5b: alerts fire early enough to act before a forced abort, the mission keeps running through the intervention, and the operator decides continue-or-recover. This addendum does not change ROV behaviour — it is already covered by DIR-5b — it clarifies that AUV needs an equivalent, currently unspecified, autonomous response. **Must:** Treat in-mission AMBER as requiring a response, not just a display state, in both modes — the response mechanism differs (autonomous decision vs. operator handoff), but neither mode may treat in-mission AMBER as purely informational. **Must not:** Assume AMBER can be left unhandled until it escalates to RED. That defeats the purpose of an early, actionable warning (DIR-5b). > **Status:** Intent recorded, not implemented. AUV's autonomous curtailment logic is > unspecified pending further design (see Parked Design Items). --- ## DIR-9 — Recording is continuous and independently guarded — **SUPERSEDED by DIR-9a** > ⚠ **SUPERSEDED (9 Jul 2026).** The continuous-from-boot model below is NO LONGER the governing > intent. It was over-specified: it records hours of pre-dive bench idle, and it decouples the > recording from the thing being recorded (the armed run). **DIR-9a governs.** This entry is > retained for history and because `recording_manager.py` still implements it — that is drift, > not intent. The two durable ideas carried forward into DIR-9a are: (1) the recorder is a > **separate node** from `mission_executor`, and (2) **recorder-active is a precondition** for > mission start in AUV mode. ### Superseded text (DIR-9, June 2026) **Source:** AUV/ROV lifecycle research (project doc: Mission_and_Data-Recording_Lifecycle...), June 2026. Aligns owner intent with proven practice. **Intent:** Data recording is a **dedicated, always-on process**, separate from the mission executor. It is brought active *before* any mission can start and runs continuously through manual control, mission execution, return-to-safe, and recovery. This is the dominant pattern across ArduPilot/ArduSub (pre-arm fails if logging fails), MBARI LRAUV (continuous background logging), QGroundControl (GCS-level auto-save), and MOOS-IvP (separate pLogger process). **Two failure modes this prevents:** 1. "Mission ran but nothing recorded" — prevented by making recorder-active a precondition for mission start (hard no-go, like ArduPilot's "PreArm: Logging failed"). 2. "Continuous recording filled the disk" — prevented by bag splitting (max size/duration), zstd/lz4 compression, and a retention/circular policy (delete-oldest below a free-space threshold). **Architecture:** - Recording runs as a **dedicated ROS2 lifecycle node ("recording manager")**, separate from `mission_executor`, managed Nav2-style and brought to `active` before missions can start. - The recorder is a real **rosbag2 MCAP recorder** (or Foxglove SDK MCAP sink), controlled via its services (`~/pause`, `~/resume`, `~/split_bagfile`, snapshot mode). - **CORRECTION TO PRIOR DOCS/MEMORY:** "MCAP recording via foxglove_bridge" is WRONG. `foxglove_bridge` is a live-visualisation WebSocket bridge ONLY — it does not record MCAP. The recorder and the bridge are separate nodes running alongside each other. This error must be corrected wherever it appears (handover, memory). **Must:** - Run the recorder continuously, independent of mission state. - Block mission start if the recorder is not active; surface recorder health in the operator UI and treat a recorder fault like a failsafe (warn). - Split bags on mission-phase boundaries; annotate bags with mission metadata (YAML, schema version, vehicle/firmware IDs, active profile). **Must not:** - Bind recorder liveness to mission start/stop. - Use foxglove_bridge as the recording mechanism. --- ## DIR-9a — Recording is a single ARM-bounded black-box tier (GOVERNING) **Source:** Grant, July 2026. Supersedes DIR-9. **Intent:** There is **one** recording tier, and it is bounded by the **armed run** — not by boot, not by mission state. Its purpose is **black-box / debug / ML / fault-finding**. It is the flight recorder: it covers the period in which the vehicle can move. **Behaviour, keyed to the `recording_control` flag (not the mode name):** - **AUV (`auto`)** — recording **starts on ARM, stops on DISARM**. No operator is present; the vehicle records its own armed run. - **ROV (`manual`)** — the **operator starts and stops** recording. On the ARM edge, if the recorder is not active, the Recording Control widget raises a reminder ("armed, not recording"). Keyed to `record_reminder_on_arm`. **No-go coupling, keyed to the `nogo_gate` flag:** - **AUV (`enforced`)** — a recording failure is a **hard no-go**. Mission stops; vehicle is recovered. - **ROV (`relaxed`)** — a recording failure after ARM alerts the pilot; the operator resolves it in-water or recovers. Not a hard stop, because a human is in the loop. **Must:** - Bound recording to the armed run, per armed run. - Derive behaviour from the `recording_control` / `nogo_gate` flags, never from a mode string. - Keep the recorder a **separate node** from `mission_executor` (carried forward from DIR-9). - Split bags, compress, and enforce a retention policy — the disk-fill failure mode from DIR-9 remains real and its mitigations still apply. **Must not:** - Record continuously from node startup, independent of ARM state. - Treat recorded data as a **client deliverable**. Certified deliverable capture is OUT of scope pending Class-approved devices. Recorded data is dev/debug/ML only. - Use `foxglove_bridge` as the recording mechanism (carried forward from DIR-9 — it is visualisation only). > ⚠ **Implementation drift (9 Jul 2026):** `recording_manager.py` still implements DIR-9 > (continuous-from-boot). `foxglove_mcap.launch.py` comments also still cite DIR-9. Additionally > `argonaut-stack.sh` passes `record:=${RECORD}` to a launch file that declares no such argument, > so `RECORD=false` is silently ignored and bags record regardless. A dedicated DIR-9a rework is > required. Do NOT wire `RECORD` into the current DIR-9 model. --- ## DIR-10 — Record intent lives in the mission plan; runtime override allowed **Source:** AUV/ROV lifecycle research + Grant's "checkboxes for what to record" requirement, June 2026. **Intent:** *What* gets recorded is decided primarily at **plan time**, embedded in the mission, with **runtime operator override** always available. This mirrors the universal pattern (ArduPilot in-mission camera DO-items, LRAUV `Enabled` arguments, QGC plan-attached camera actions) where default capture is planned but the operator can always start/stop/split/add/drop a stream live. **Representation:** - A **`recording:` block in the mission YAML** carrying named **record profiles** (e.g. `nav_only`, `inspection_full`) and **per-stream toggles** (forward camera, sonar, CTD, navigation, etc.). This is Grant's checkbox concept — surfaced in the mission planner UI, stored in the mission file. - At execute time, the profile translates into (a) the rosbag2 recorder's topic set and (b) any MAVLink camera `DO_*` items — the same YAML→`MISSION_ITEM` translation already done by `rov_mission`. - A **low-rate always-on core** (vehicle state, mode, mission status, nav) records continuously regardless of profile; the profile governs the **high-rate sensor streams**. **Must:** - Let the operator choose record streams at plan time (checkboxes / profiles in the planner UI). - Allow runtime override from the console (start/stop/split/snapshot, add/drop a stream). - Keep the always-on core recording regardless of selected profile. **Must not:** Require the operator to configure recording separately from the mission for the common case — the plan should imply its data products. **UI note:** This is where the checkbox UI Grant described lives — in the mission planner (plan-time), with a runtime override surface on the operator console. The 3D Mission Planner (deferred to Phase 6+) is the eventual home; an interim plan-time mechanism may be needed sooner. --- ## DIR-12 — Vehicle health and autonomy health are distinct; the operator must see both **Source:** Grant + measured failure, 9 July 2026. **Origin:** With the flight controller unreachable ("No board running" in BlueOS), **W1 displayed GREEN / "Systems nominal"**. Every widget indicator was reporting on the RPi5 autonomy stack, not on the vehicle: - **W1** reads the failsafe assessment, which does not gate on FC connectivity. - **W8** reads the active mode profile, sourced from a YAML file — it would show `AUV` with the Pixhawk sitting in a drawer. - **Foxglove "Connected: true"** means connected to `foxglove_bridge` on the RPi5, not to the vehicle. **Intent:** "Health" is not one thing. There are two independent subjects, and conflating them produces a display that is confidently wrong at the worst moment: 1. **Autonomy health** — the RPi5 stack: nodes alive, EKF converged, recorder active, bridge up. 2. **Vehicle health** — the FC and the platform: FC reachable, heartbeat fresh, arm state known, sensors reporting, power sane. **Must:** - Assess vehicle health as a first-class input to the failsafe state (see DIR-7). - Make the *subject* of any health indication unambiguous to the operator — a green light must answer "green about what?". - Treat loss of FC communications as a vehicle-health RED regardless of how healthy the autonomy stack is. The autonomy stack being perfectly well is irrelevant if it is talking to nothing. **Must not:** - Allow an indicator that reads only autonomy state to be presented as overall system health. - Allow an AUV pre-dive gate (DIR-7, `health_role: gate`) to pass without a verified FC link. - Rely on the operator having a second tool (BlueOS, QGC) open to know whether the vehicle is alive. In AUV mode nobody is watching; pre-dive, the gate must be self-sufficient. **Related, same class of failure:** the BlueOS `ardupilot_manager` `/dev/i2c-1` FD leak (`docs/handover.md` §15a) can silently exhaust the FC-management service after ~11 h of cumulative board-config page exposure. The FD count does not reset at launch. A pre-dive gate that checks FD headroom on `ardupilot_manager` belongs here, alongside the FC-link check — both are "is the vehicle actually going to keep talking to me" questions. > **Status:** OPEN. Not implemented. Safety-critical for AUV mode. --- ## DIR-13 — Widget-to-hardware ownership map **Source:** Grant, 14 Jul 2026 session. **Intent:** Record, as owner-stated intent, which physical subsystem (RPi4 BlueOS gateway vs RPi5 autonomy brain) each Cockpit widget actually reflects — the wiring picture behind the UI, so it is not left to be inferred from code. Relates directly to DIR-12 (vehicle health and autonomy health are distinct subjects) — this DIR is the widget-level instance of that same distinction, enumerated per widget rather than argued in the abstract. **W1 (System Health Indicator) is a two-stage health gate, not a single-subsystem readout:** 1. **Flight-controller heartbeat (RPi4 gateway) MUST pass first.** A dead or unreachable FC makes autonomy meaningless regardless of how healthy the RPi5 stack is — this is DIR-12's "vehicle health is distinct from autonomy health" applied concretely. **Already implemented** (commit `86b2728`, 11 Jul 2026) — `failsafe_monitor` forces RED on FC comms loss. 2. **RPi5 autonomy-stack self-health** — nodes alive, EKF converged, recorder active, bridge up — is the second stage. **Not yet built.** Only when both stages pass is W1 GREEN. W1 is not "an RPi5 stack indicator" and never was intended to be one — the FC-heartbeat stage is what makes it a *vehicle* health gate rather than an *autonomy* health gate (DIR-12). **Per-widget ownership (owner-stated intent):** - **W1 (System Health Indicator)** — BOTH: RPi4 (FC heartbeat, implemented) + RPi5 (autonomy self-health, not yet built). See above. - **W2 (Mission Status)** — RPi5 (`mission_executor`). - **W3 (Return To Safe button)** — RPi5 (`failsafe_monitor` via `/rov/mission/abort`). - **W4 (Mission Setup button)** — RPi5 (FastAPI setup page, not yet built). - **W5 (Return Budget)** — RPi4. Reflects the battery, which is connected to the RPi4 (via MAVROS/Pixhawk), not the RPi5. - **W6 (Altitude)** — RPi5. **Deliberately** kept sourced direct from the RPi5 (Ping2 on RPi5), not routed via the RPi4 — consistent with the principle that the autonomy unit should be standalone, with BlueOS/Cockpit integration as its only current external dependency. - **W7 (Backup Due Notice)** — RPi5 (+ server, Option A design). Specced, not built. - **W8 (Mode Indicator)** — RPi5 (`mode_profile_loader`). **Must:** Keep this ownership map in sync with `docs/handover.md`'s current-state material — that document carries the same table for quick operator reference; this entry is the intent record, that one is the live status pointer. **Must not:** Let a widget's *apparent* subject (what it visually looks like it's reporting on) diverge from its *actual* data source without recording the divergence here — this is exactly the DIR-12 failure mode (a green light that doesn't say what it's green about). --- ## DIR-14 — Depth is a dual-source, operator-selectable input **Source:** Grant, 14 Jul 2026 session. **Intent:** Depth may be sourced from a sensor on the RPi4 (via the flight controller) OR a sensor added directly to the RPi5, and the system should support selecting one source, the other, or a blend of both — chosen at mission setup time (associated with the W4 Mission Setup widget) and carried in the resolved configuration the same way other mode-profile settings (e.g. `health_role`) are, not hardcoded. **Rationale — redundancy plus operator choice:** Two independent depth sources give a fallback if one fails, and let the operator (or the setup wizard) pick whichever is more trustworthy for a given deployment, rather than the system being permanently committed to one sensor's data path. **Consistent with the standalone-autonomy principle (see DIR-13):** an RPi5-direct depth sensor means the RPi5 autonomy unit is not solely dependent on the RPi4 for this input — the same reasoning already applied to W6 altitude. **Must (once built):** Read the selected depth source (RPi4 / RPi5 / blend) from the resolved mode profile, the same mechanism `health_role` and the other mode-profile flags already use — never hardcode a single source. **Must not:** Assume depth always comes from one fixed sensor path. Both paths are legitimate; the choice is a configuration, not a constant. > **Status:** Design-captured intent for a future build. Not yet specified in detail — no > sensor selection mechanism, blending algorithm, or config-profile field decided here, only > the shape of the requirement (dual-source, operator-selectable, mode-profile-carried). --- ## Parked Design Items (intent-adjacent, not yet actioned) Tracked here so they aren't lost between sessions. Not full DIR entries — each is an implementation gap against an existing DIR, recorded so the next session that touches the relevant code knows the decision is already made in principle, just not built. ### Auto-recovery (relates to DIR-7, DIR-12) `failsafe_monitor` should attempt to **re-establish the FC link itself** before escalating — holding or forcing RED only if it cannot restore comms. Real-world dives have no operator to restore the connection manually; the current implementation (11 Jul 2026 fix) correctly detects and reports loss but does not attempt recovery on its own. This is distinct from the FSM's condition-clear recovery (which reacts once the condition is already gone) — auto-recovery is about the monitor actively trying to make the condition go away. ### Dedicated `string cause` field (relates to DIR-7's "state must carry its cause" MUST) `FailsafeStatus.msg` currently carries cause information as a substring of `message` (`cockpit_bridge` splits on the first `|`), not a first-class field. Add a dedicated `string cause` field to `FailsafeStatus.msg` and have `cockpit_bridge` read it directly, retiring the substring-parsing shortcut. Same intent as already specified in DIR-7; this is purely a mechanism cleanup, not a new decision. ### Mode-aware safe-zone-reached arrival event (relates to the DIR-7 addendum, "In-mission recovery is mode-dependent") Gate-mode (AUV) committed recovery, once entered, **runs to completion** (per the addendum above) and must be signalled complete by an **arrival event**, not by the triggering condition merely clearing — condition-clear and arrival are different facts, and conflating them would let a transient blip that clears immediately end a recovery the vehicle has not actually completed. **Permanent interface:** the topic `/rov/nav/safe_zone_reached` (`std_msgs/Bool`), which `failsafe_monitor` subscribes to and which the **navigation subsystem** will publish to. This topic and the subscription to it are permanent — `failsafe_monitor` must only ever consume this event, never compute position itself; that responsibility belongs to navigation. **The arrival judgement is mode-aware and sensor-derived, not a single fixed method:** - **GPS provides fixes at the surface**, including the pattern where an AUV takes a start fix, dives to dead-reckon a survey on sensor data, and periodically resurfaces for GPS fixes to bound drift before diving again. - **Underwater, in both modes**, the position estimate is EKF- and dead-reckoning-based — there is no GPS underwater. **GPS is a first-class part of the navigation system across mission types** — e.g. pipeline survey, which routinely involves the resurface-for-a-fix pattern above — not a marginal, surface-only concern specific to hull and jacket inspection. This corrects any earlier framing that treated it that way. **Gate-only by design:** the arrival event applies to gate (AUV) mode only. Advisory (ROV) mode keeps its existing operator-resume mechanism (see the addendum above) and ignores the arrival event entirely — there is no reason for an operator-present mode to wait on an autonomous arrival signal it does not need. **Until navigation can raise this event, its publisher is temporary throwaway scaffolding:** a W1-contextual operator button that appears only while W1 shows the recovering/`RETURN_TO_SAFE` state, backed by a `rov_api` endpoint. This scaffolding is a **dumb publisher to the topic only** — it never reaches into `failsafe_monitor` internals — so it can be deleted cleanly in one cut when navigation takes over publishing to the same permanent topic. > **Status:** Permanent interface (topic + `failsafe_monitor` subscription + FSM behaviour) > implemented 13 Jul 2026 (`bf815cc`) — see `docs/handover.md` §15f. Temporary bench-scaffolding > publisher (W1 button + `rov_api` endpoint) and the real navigation-raised event are both still > to come. ### Adaptive restart-timing (relates to the DIR-7 addendum's corrected tier-2 model; depends on the count-based retry machinery existing first) **Source:** Grant, 13 Jul 2026. Rather than a fixed restart timeout, the system should **monitor its own restore behaviour** — capturing **restore count and restore duration** each time a fault is recovered — log it, and **weigh future restart attempts against that observed history** rather than against a fixed time. **Worked example:** On a failure, the system attempts a restart. If the restart succeeds, it returns to GREEN and resumes (per the tier-2 model above), while in the background it **logs the restore**, including count and duration. If the failure **recurs**, it may attempt restart again — now **comparing against the previous attempt** — and logs the second failure. Subsequent failures are then subject to the configured acceptable-count parameter (tier 2 above). This item deliberately holds **all** the time-and-duration-based sophistication (rolling windows, learned durations, weighing attempts against history) that was **kept out of** the count-based correction above — the corrected DIR-7 addendum trigger is a raw count, on purpose, precisely so it does not depend on this not-yet-built machinery. This item **depends on** the count-based retry machinery existing first; it is not a substitute for it and cannot be built ahead of it. > **Status:** Design-captured intent for a dedicated future session. **Not yet specified for > build** — no algorithm, thresholds, or storage format decided here, only the shape of the > problem and its dependency ordering. --- ## Proposed build staging (REVISED to align with research) Derived from the above and the lifecycle research; tethered-first since initial development is tethered. Reordered because the recording manager is foundational — it must be active before any mission can start (DIR-9). - **Stage 1 — Recording Manager (foundational):** dedicated ROS2 lifecycle node running a rosbag2 MCAP recorder, **ARM-bounded per DIR-9a** (not continuous — the original "continuous" wording here reflected the superseded DIR-9), separate from mission_executor. Bag splitting, compression, retention policy, health surfaced to UI. Recorder-active becomes a precondition for mission start. (Replaces the prior "MCAP via foxglove_bridge" assumption.) CREATE-THEN-BACKUP applies. - **Stage 2 — Mission Start/Stop:** mission-layer command via the existing `MissionCommand` service (START/ABORT/PAUSE/RESUME/LOAD already implemented). Splits the bag on mission boundaries; applies record profile. Does not move vehicle, does not stop the recorder. - **Stage 3 — Record profiles + intent in mission YAML:** the `recording:` block (DIR-10), profiles and per-stream toggles, translated at execute time. Includes the checkbox UI surface. - **Stage 4 — Condition detection + alerting:** autonomy detects designated levels exceeded; raises alert (AUV acts; ROV surfaces alert to operator). - **Stage 5 — Return-to-Safe + HILT override:** vehicle return-to-safe (auto in AUV, intervenable in ROV); recorder continues through transit, bag split on phase boundary. - **Stage 6 — Config UI:** threshold parameters ("designated levels") governing Stage 4/5; also the W5 return-budget constants (DIR ties to battery floor + reserve). - **Stage 7 (SHELVED) — Emergency Surface.** **Note on existing code:** `mission_executor` already implements the `MissionCommand` service (START/LOAD/PAUSE/RESUME/ABORT) and failsafe integration (emergency-surface and return-to-safe both abort the mission). It does NOT control recording — correct per DIR-9. Stage 2 wires Mission Start/Stop to this existing service plus bag-split calls to the Stage 1 recorder. --- ## Implications for existing code/widgets (factual, for validation) - The currently wired `/rov/mission/abort` (Bool → failsafe_monitor → flag_manual_abort → state machine) matches the **AUV automatic** path (DIR-5 AUV mode). It does NOT implement the tethered HILT intervention model (DIR-2/DIR-5 ROV mode), which is the near-term need. - `mission_executor` implements the `MissionCommand` **service** (not a topic): commands START/LOAD/PAUSE/RESUME/ABORT, request `{command, mission_id, parameters[]}`, response `{success, message}`. Mission Start/Stop (DIR-4, Stage 2) drives this. - `mission_executor` does **not** control recording — correct per DIR-9a. Recording is a separate Stage-1 manager. - **W1 reports GREEN with the flight controller unreachable (DIR-12, DIR-7).** `failsafe_monitor` does not consume `/mavros/state` connectivity. OPEN, safety-critical. - **`recording_manager.py` implements superseded DIR-9, not governing DIR-9a.** OPEN. - **"MCAP via foxglove_bridge" is WRONG (DIR-9).** foxglove_bridge is viz-only. Correct this in the handover (Tools section, Section 8/11) and in memory. Recording = rosbag2 MCAP recorder, separate node. - **W3 button label "ABORT MISSION" is misleading** per DIR-5 — implies emergency hard-stop but maps to assessed return-to-safe. Rename pending — exact wording TBC with Grant. - **W2/W4 mission state** relates to DIR-4 (mission start/stop), mission-layer, distinct from DIR-5 vehicle action.