rov-autonomy/docs/design_intent_register.md
Grant 255096f20b docs(dir): correct inverted DIR-7 in-mission-recovery intent to count-based fault-persistence model
The 11 Jul DIR-7 addendum "In-mission recovery is mode-dependent" stated
that AUV gate mode commits to recovery ON CONDITION-CLEAR. That was
inverted and wrong — it produced a contradictory GREEN-while-in-
RETURN_TO_SAFE state observed live.

Corrected intent (v1.4, 13 Jul 2026, attributed to Grant):
- GREEN is unconditionally a working state. A cleared fault returns the
  vehicle to GREEN and the mission continues/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.
- Three-tier fault model: (1) uncontrollable — power loss / anything that
  disables the safety logic itself, out of scope for the FSM, adjacent to
  shelved DIR-6; (2) transient/self-resetting — system attempts restore,
  returns to GREEN and resumes on success, each failure increments a raw
  count (deliberately no time window/duration), commits to RETURN_TO_SAFE
  only once the count exceeds a configured acceptable number; (3)
  hard/persistent — a RED that doesn't clear, commits immediately without
  waiting on a count.
- All thresholds (acceptable count, transient-vs-hard classification) are
  configuration-driven via the resolved mode profile, same as health_role,
  never hardcoded.
- Survives, correct: health_role mode-awareness (2a3e577); the
  safe-zone-reached arrival-exit mechanism (bf815cc) — its role (completing
  a committed recovery) is unchanged. Retired, known-wrong: 2a3e577's
  condition-clear entry logic, which bf815cc built its exit on top of —
  pending next-session rework into the count-based model. Only the ENTRY
  into committed recovery was wrong, not the exit.

New Parked Design Item: adaptive restart-timing — monitor own restore
count/duration per fault, log it, weigh future restart attempts against
observed history rather than a fixed time. Deliberately holds all
time/duration sophistication kept out of the count-based correction;
depends on the count-based retry machinery existing first. Design-captured,
not yet specified for build.

Changelog and known-implementation-drift callout updated accordingly —
failsafe_monitor's current condition-clear logic is now flagged as a known
implementation gap pending rework, not merely an unimplemented addendum.

Documentation only — no code or widget files touched. Not uploaded to
Claude project knowledge; that remains a manual step.
2026-07-13 18:02:42 +02:00

45 KiB

Design Intent Register — Argonaut 3

Version: 1.4 Date: 13 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.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_RECOVERRETURN_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<Instrument> 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.


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.