scripts/data_migrations/relabel_oura_hrv_sdnn_to_rmssd.py
Problem
Oura reports RMSSD-based HRV, but the ingestion path historically stored those values under the SDNN series type (id=3) instead of RMSSD (id=7). The numeric values are correct — only the metric label (and therefore its unit semantics) was wrong.
The ingestion path was fixed separately in backend/app/services/providers/oura/data_247.py, so new Oura HRV samples are now stored as RMSSD. This script corrects pre-existing rows in data_point_series and data_point_series_archive.
What it does
Forprovider='oura' rows only, it relabels every HRV series from SDNN (id=3) to RMSSD (id=7). The scope is strict — other providers’ genuine SDNN data (e.g. Apple, Ultrahuman) is left untouched.
Both data_point_series and data_point_series_archive are updated.
Conflict handling
After the ingestion fix, a re-sync can write a correct RMSSD row at the same key as an old SDNN row, which would collide with the unique constraint on relabel:data_point_series— unique on(data_source_id, series_type_definition_id, recorded_at)data_point_series_archive— unique on(data_source_id, series_type_definition_id, bucket_start_at, aggregation_type)
Idempotency
Once relabeled, rows no longer match the SDNN filter, so re-runs are no-ops. The script is wired into container startup (scripts/start/app.sh) and runs automatically on every deploy until removed.
This script is scheduled for removal after 2026-09-01, once all deployments have migrated.
Usage
Options
| Flag | Description |
|---|---|
--dry-run | Print how many rows would be relabeled and how many duplicates would be removed. No changes made. |
Dry run output
Related
- Commit
3bcf2973— the ingestion fix (oura/data_247.py) that stores new Oura HRV as RMSSD. - Coverage Matrix — Oura HRV is listed under
heart_rate_variability_rmssd.

