> ## Documentation Index
> Fetch the complete documentation index at: https://developer.neurofit.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Diagnostics

> The keys in VitalsResult.diagnostics, what each one records, and which are platform-specific.

Every `VitalsResult` carries a `diagnostics` object: capture and quality values recorded at the end of the
reading. They exist for support and for your own analytics (for example, slicing withheld rates by device model
or torch state). They are not user-facing metrics.

The native `VitalsDiagnostics` type exposes each key as a camelCase property and serialises to the snake\_case
keys below (`toDictionary()` on iOS, `toMap()` on Android; the wrappers deliver the snake\_case map). Store the
whole object with the result; NEUROFIT support will ask for it.

<Note>
  Values in the "engine" group are defined by the engine and can change meaning between engine versions. Treat
  them as opaque unless NEUROFIT asks for them; do not build product logic on them. `engine_version` tells you which
  definitions apply. This page documents the key union and the type of each value; it does not describe how the
  engine computes them.
</Note>

Conventions: a numeric `-1` means "not available". Keys marked optional are absent (not `-1`) when the step that
produces them did not run. Platform column: **both** unless noted.

## Provenance

| Key | Type | Platform | Meaning |
| - | - | - | - |
| `engine` | string | both | Always `neurofit_vitals`. |
| `engine_version` | string | both | Engine version, `1.3.0` for this release. |
| `effective_fps` | int | both | Frame-rate tier the reading ran at: 60, 30 or 20 on iOS; 30 on Android. |
| `hr_source` | string | both | Engine-defined string. Opaque. |
| `refine_mode` | string | both | A per-platform engine constant. Opaque. |

## Quality

| Key | Type | Platform | Meaning |
| - | - | - | - |
| `signal_quality` | int | both | 3 clean, 2 usable, 1 withheld. Same as `result.quality`. |
| `quality_passed_fraction` | 0 to 1 | both | Fraction of the reading's windows that passed the live quality check. |
| `discard_ratio` | number | both | Share of the reading's beat intervals set aside as unreliable; an input to the quality tier. |
| `amplitude` | number | both | Pulse amplitude of the signal, in engine units. |
| `snr_db` | number | both | Signal-to-noise ratio, dB. |
| `saturation_frac` | 0 to 1 | both | Part of the camera's exposure operating point. Values near 1 usually mean a hard press or a very bright torch. |
| `measured_fps` | number | both | Frames per second actually delivered over the measuring window. |
| `frame_interval_cv` | number | both | Coefficient of variation of the inter-frame interval (frame-timing jitter). |
| `frame_drop_compliance_error_count` | int | both | Number of previews that reported `frameDrop` during this attempt, positioning and measuring alike. Reset on every re-arm, kept when measuring starts. |

## Quality trajectory

How the signal evolved during the reading, for tuning your guidance and for support.

| Key | Type | Platform | Meaning |
| - | - | - | - |
| `live_sq_at_15s` | number | both | Live signal-quality estimate at 15 s. |
| `live_sq_at_30s` | number | both | Live signal-quality estimate at 30 s. |
| `early_mean_quality_score` | number | both | Mean quality score over the early part of the reading. |
| `early_min_quality_score` | number | both | Lowest quality score over the early part of the reading. |
| `early_mean_amplitude` | number | both | Mean pulse amplitude over the early part of the reading. |
| `early_mean_discard_ratio` | number | both | Mean discard ratio over the first five live estimates. |
| `early_max_discard_ratio` | number | both | Highest discard ratio over the first five live estimates. |
| `live_sq_max_withheld_run` | int | both | Longest run of consecutive withheld live estimates. |
| `live_sq_withheld_estimates` | int | both | Number of live estimates that were withheld. |
| `live_sq_total_estimates` | int | both | Number of live estimates produced. |
| `live_sq_withheld_seq` | string | both | The live estimates in order, encoded as withheld or kept. |

## Capture hardware

The camera's operating point at the end of the reading. Exposure is fixed during a reading, so this equals the
reading's settings.

| Key | Type | Platform | Meaning |
| - | - | - | - |
| `torch_active` | bool | both | Torch was on. |
| `torch_level` | number | both | Torch level 0 to 1. iOS reports the actual level; Android reports 1.0 or 0.0 (binary torch). |
| `exposure_iso` | number | both | Sensor ISO. iOS reads it back from the camera; Android reports the value the SDK set. |
| `exposure_duration_ms` | number | both | Exposure duration, ms. |
| `exposure_locked` | bool | both | Exposure was fixed for the reading. |
| `exposure_tuner_enabled` | bool | iOS | Whether the exposure tuner was on (off in production on iOS). |
| `exposure_tune_steps` | number | iOS | Exposure adjustments made before the reading started. |
| `red_dc_mean` | number | iOS | Part of the camera's exposure operating point during the reading, 0 to 255. |
| `active_format_width` | int | iOS | Width of the camera format used. |
| `active_format_height` | int | iOS | Height of the camera format used. |
| `is_video_binned` | bool | iOS | Sensor binning in use for the format. |
| `video_field_of_view` | number | iOS | Horizontal field of view of the format, degrees. |
| `lens_position` | 0 to 1 | iOS | Where autofocus parked before it was locked. |
| `minimum_focus_distance` | int | iOS | Minimum focus distance, mm. |

## Breathing

| Key | Type | Platform | Meaning |
| - | - | - | - |
| `motion_samples` | int | both | Accelerometer samples that reached the engine. 0 when `motionBreathing` is off or the device has no accelerometer. |
| `rr_motion_brpm` | number, optional | both | Breathing rate estimated from the phone's motion. Absent when there was too little motion data. |
| `rr_motion_conc` | number, optional | both | Confidence of the motion-derived breathing rate, 0 to 1. |

## Engine

Engine-defined values. Opaque; see the note at the top. The three `*_enabled` keys mirror configuration flags;
the rest are the engine's own features and intermediate values, recorded so that NEUROFIT can reproduce a
reading's outcome from its diagnostics.

| Key | Type | Platform | Meaning |
| - | - | - | - |
| `spectral_concentration` | 0 to 1 | both | A signal-quality feature. Opaque. |
| `skewness` | number | both | A signal-quality feature. Opaque. |
| `gate_enabled` | bool | both | Mirrors `consistencyGate` in the configuration (true in production). |
| `gate_merged_fix_enabled` | bool | both | Mirrors `mergedIntervalFix` in the configuration (true in production). |
| `est_android_estimator_enabled` | bool | Android | Mirrors `androidEstimator` in the configuration (true in production on Android). |
| `gate_rejected` | bool, optional | both | The consistency check withheld HRV (RMSSD) and the related metrics (`flags` contains `consistency_gate_rejected`). |
| `gate_veto` | bool, optional | both | Engine-defined. Opaque. |
| `gate_n_pairs` | int, optional | both | Engine-defined. Opaque. |
| `gate_n_merged` | int, optional | both | Engine-defined. Opaque. |
| `gate_discard_raw` | number, optional | both | Engine-defined. Opaque. |
| `gate_max_jump` | number, optional | both | Engine-defined. Opaque. |
| `gate_hf_share` | number, optional | both | Engine-defined. Opaque. |
| `gate_compress` | number, optional | both | Engine-defined. Opaque. |
| `gate_r_ps` | number, optional | both | Engine-defined. Opaque. |
| `est_col_over_prod` | number, optional | both | Engine-defined. Opaque. |
| `est_rmssd_parabolic` | number, optional | both | Engine-defined, ms. Opaque. |
| `est_rmssd_fixed` | number, optional | both | Engine-defined, ms. Opaque. |
| `est_gm_ratio` | number, optional | Android | Engine-defined. Opaque. |
| `est_gm_applied` | bool, optional | both | Engine-defined. Opaque. |
| `est_arm2_fired` | bool, optional | both | Engine-defined. Opaque. |

## Cancel context

`cancelled(reason, context)` carries a smaller set with the same conventions, describing the moment of the
cancel. `CancelContext.toDictionary()` (iOS) / `toMap()` (Android) always has these ten keys: `reason`
(`contact_lost`, `low_quality`, `low_live_signal_quality`, `no_low_discard_estimate`, or your host string),
`quality_score`, `elapsed_s`, `engine`, `refine_mode`, `effective_fps`, `device_model`, `red_dc`, `exposure_iso`
and `exposure_tune_steps`, with `-1` for an absent number; `exposure_in_band` is added only when it is known.
`red_dc` is the red mean of the last frame (the attempt's mean is `red_dc_mean` in the result diagnostics);
`exposure_tune_steps` is always `-1` on iOS, which runs auto-exposure. Log it if you want to understand abandoned
attempts, which never produce a result.

## Using diagnostics in your analytics

Useful slices, in the order they tend to pay off:

1. Withheld rate by `device_model` (from your own device info) and `effective_fps`.
2. Withheld rate against `saturation_frac` (users pressing too hard) and `amplitude` (cold fingers, thick cases).
3. `measured_fps`, `frame_interval_cv` and `frame_drop_compliance_error_count` on devices that report `frameDrop` or recoverable errors.
4. `torch_active == false` on completed readings, which points at a torch problem on that model.

Keep `engine_version` and the result's `sdkVersion` with every row so definitions can be matched to a release.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.