Skip to content

Safety Principles

DiveSuite handles decompression calculations that, if incorrect, can cause serious injury or death. This document defines our non-negotiable safety principles.

All decompression calculations are meant to happen in a single, isolated Rust crate. Decision D27 (planned) makes Rust the only deco engine. Until then the TypeScript fallback still computes plans on every platform, because WASM is disabled on the web. The fallback is not validated against Subsurface; it refuses every input it cannot model (bridge-fallback-scope.ts) and never supplies stops of its own:

+-------------------------------------+
| Application |
+-------------------------------------+
| Service Layer |
+-------------------------------------+
| +-----------------------+ |
| | Deco Engine | <- Only module that
| | (Rust) | touches tissue
| | | loading calculations
| | - Buhlmann ZHL-16C |
| | - NDL calculation |
| | - Gas physics |
| +-----------------------+ |
+-------------------------------------+

Rules:

  • Only the deco engine performs tissue loading calculations
  • The engine has a clean API boundary (Input -> Output)
  • No direct manipulation of engine internals from outside
  • Engine code is changed only on the owner’s explicit request, in its own PR, with an independent safety review
  • Planned (D27): if no Rust engine runs, the app refuses to plan (see below) and no second engine takes over

AI is strictly advisory. AI cannot:

  • Generate decompression schedules
  • Modify gradient factors without user confirmation
  • Suggest exceeding MOD, NDL, or ppO2 limits
  • Override safety warnings
  • Bypass the validation layer

Architecture:

User Input -+--------------------------------------> Validation -> Deco Engine -> Plan
| ^
+-> AI Service -> Suggestions -> User Review --+
(advisory) (required)

AI output is always treated as unverified user input that must flow through normal validation.

Every dive plan output includes a mandatory disclaimer:

Implementation:

  • The disclaimer is never removed from planning screens. It may use progressive disclosure: a compact inline hint with expandable detail, or a one-time acknowledgment stored in settings. It must always stay accessible
  • First-launch acceptance is recorded with a timestamp

Before release, the deco engine must be validated:

  • Unit tests: every Rust function has a unit test, with a 95%+ coverage target
  • Property-based tests: verify invariants (for example, NDL never grows with depth)
  • Cross-reference: compare against Subsurface (same algorithm)

What we validate against:

Reference Purpose Tolerance
Subsurface Same algorithm (Buhlmann ZHL-16C), deco schedules 1 min per stop, 2 min total runtime
Subsurface No-stop limits 1 min
PADI RDP, US Navy, NOAA Upper bound for no-stop limits The engine’s NDL is never longer than the shortest published value

What we do NOT claim:

  • Equivalence with PADI tables (they use DSAT, not Buhlmann). The tables only bound the engine’s NDL from above
  • VPM-B support (not available; a clean-room version is planned, D5, P1-17)
  • Medical device certification
  • Guarantee of diver safety

5. Refuse When No Engine Runs (planned, D27)

Section titled “5. Refuse When No Engine Runs (planned, D27)”

Target state (decision D27): where no Rust engine runs, the planner and every screen that needs the engine show only a persistent, non-dismissible “engine unavailable” card that says nothing was checked (planned, DIV-115). This covers iOS until the native module ships (P1-15), Android until after Release 1, Expo Go, a failed load and a crashed engine instance. No plan, value or gas warning is shown, and no TypeScript check runs in its place. This is an owner exception to the warning rules, since without a plan there is no computed warning. The card will be a safety alert that is never hidden and never dismissible. The TypeScript fallback is removed as soon as Rust computes on the web. Until then a persistent fallback notice is planned (P1-19), and every Rust error will map to a refusal (P1-18).

Core safety features work without internet:

Feature Offline Online Required
Dive planning Yes -
Dive logging Yes -
Profile visualization Yes -
Safety disclaimers Yes -
AI suggestions No Yes
Cloud sync No Yes
Community features No Yes

When offline:

  • AI features are disabled (not erroring)
  • UI clearly indicates offline status
  • All local data remains accessible

The engine lives in rust-engine/. Inputs are validated at the Rust boundary (rust-engine/src/validation.rs) and invalid input is refused with a typed DecoError. The Rust engine does not return a plan for a refused input. The TypeScript bridge (src/core/engine/) does not yet fully honour this: it still turns most Rust errors into a fallback plan, until the refusal mapping lands (planned, P1-18).

AI output is treated as unverified user input. The AIService interface is in src/features/ai/services/types.ts. AI suggestions go through the normal validation path and the deco engine before they affect a plan.

The following actions are explicitly forbidden in DiveSuite code:

Action Why Forbidden
Disable disclaimer display Legal and safety requirement
Allow AI to modify deco output Safety boundary violation
Suppress safety warnings Could hide critical information
Skip validation in production Could allow unsafe plans
Hide or dismiss the “engine unavailable” card (once it exists, planned D27) The user would not know that nothing was checked
Use any in deco-related TS Type safety is critical
Use panic! on bad input in deco Rust Must return a typed error

When a safety issue is discovered:

  1. Assess severity – Can this cause injury?
  2. Notify users – In-app notification for critical issues
  3. Force update – CC-09 mechanism for safety-critical fixes
  4. Fix and test – Including regression test
  5. Disclose – Document in release notes
  6. Post-mortem – How did this pass testing?