From d467fd7c9a9772ff7806cd66cff052070c7a4d2b Mon Sep 17 00:00:00 2001 From: Alex Wagner Date: Fri, 16 Oct 2026 17:43:20 +0200 Subject: [PATCH 01/10] fix: retain interrupted main sleep without counting legacy naps twice --- lib/compute/accepted_naps.dart | 24 +++++- lib/compute/derivation_engine.dart | 9 ++- lib/data/db.dart | 9 ++- pubspec.lock | 6 +- pubspec.yaml | 6 +- test/accepted_naps_test.dart | 79 +++++++++++++++++++ test/activity_review_regression_test.dart | 4 +- test/activity_review_test.dart | 40 ++++++++++ .../fixtures/whoop_freeze/gen4_minus0400.json | 18 ++--- test/fixtures/whoop_freeze/gen4_plus0530.json | 18 ++--- test/fixtures/whoop_freeze/gen4_utc.json | 18 ++--- .../fixtures/whoop_freeze/gen5_minus0400.json | 18 ++--- test/fixtures/whoop_freeze/gen5_plus0530.json | 18 ++--- test/fixtures/whoop_freeze/gen5_utc.json | 18 ++--- 14 files changed, 220 insertions(+), 65 deletions(-) create mode 100644 test/accepted_naps_test.dart diff --git a/lib/compute/accepted_naps.dart b/lib/compute/accepted_naps.dart index 3fa991f3a..1625a3094 100644 --- a/lib/compute/accepted_naps.dart +++ b/lib/compute/accepted_naps.dart @@ -5,7 +5,29 @@ import 'nap_edits.dart'; void composeAcceptedNaps(Map bundle, List edits) { final old = bundle['naps'] as Map?; if (old == null && edits.isEmpty) return; - final accepted = applyNapEdits(const [], edits); + final sleep = bundle['sleep']; + final metric = sleep is Map ? sleep['window'] : null; + final window = metric is Map ? metric['value'] : null; + final onset = window is Map ? window['onset_ms'] : null; + final offset = window is Map ? window['offset_ms'] : null; + final hasMainWindow = + onset is num && + offset is num && + onset.isFinite && + offset.isFinite && + offset > onset; + // A corrected main window can absorb an older detector's nap snapshot. + // Suppress that legacy overlap in every total, retaining the stored entry + // for a later window correction. Manual/confirmed decisions still win. + final accepted = applyNapEdits(const [], edits) + .where( + (nap) => + nap['source'] != 'legacy' || + !hasMainWindow || + (nap['end'] as num) * 1000 <= onset || + (nap['start'] as num) * 1000 >= offset, + ) + .toList(); // Whether the detector judged the day, persisted so a later compose cannot // turn an unjudged day into a measured zero once its logged naps are gone. // Rows from before the flag: an unjudged day only carried a value when the diff --git a/lib/compute/derivation_engine.dart b/lib/compute/derivation_engine.dart index fba1cc9e6..929fead53 100644 --- a/lib/compute/derivation_engine.dart +++ b/lib/compute/derivation_engine.dart @@ -1810,7 +1810,12 @@ import 'vendor_sleep.dart'; // store `skin_temp_ambient_r` and the illness watch leaves out WHOOP 4 nights // whose skin temp tracks ambient (|r| >= 0.8, or unmeasured). One-shot, // raw-free: days derived before v106 drop naps overlapping the next night. -const int kAlgoVersion = 113; +// 113 → 114: analytics sleep-continuation fix. Main-sleep selection +// shares the detector's inclusive 90-minute continuation limit, retaining +// second sleep blocks after hour-long awakenings; gaps stay wake/unobserved. +// Legacy nap snapshots overlapping the corrected main window no longer add +// the same sleep twice. Explicit nap confirmations and restorations survive. +const int kAlgoVersion = 114; /// The sibling SHAs this version was derived against, asserted against /// pubspec.yaml in test/db_serve_version_and_reads_test.dart. /// @@ -1996,7 +2001,7 @@ const int kAlgoVersion = 113; // REPIN @ 77fe373: analytics main, #95 merge (readiness autonomic // merge + spread calibration + capped re-centring + robust lnRMSSD // centre), for v112. -const String kAnalyticsPin = '77fe373eb819fda235f80610e898a4bc20a7a249'; +const String kAnalyticsPin = '74165e45254203c5784ad88a53d8ec6ab099d6dd'; // Repinned to analytics main's tip, which carries BOTH PR #72 (hrv_freq // Welch gap guard) and PR #73 (overreachingConjunction rhr quantum guard) — // the two independent kAlgoVersion bumps above (93 and 94). Verified both diff --git a/lib/data/db.dart b/lib/data/db.dart index ed954c51b..763608951 100644 --- a/lib/data/db.dart +++ b/lib/data/db.dart @@ -12103,10 +12103,17 @@ class LocalDb { if (restoreSource != null) { // Removing a rejection means "Put it back". Keep its original asleep // minutes and confidence even after raw recordings have expired. + // This is now an explicit decision, even for a legacy snapshot: a + // later main-window correction must not suppress it as old detection. + restoreSource = 'confirmed'; + final restored = Map.from(jsonDecode( + restorePayload ?? rows.single['payload_json'] as String) as Map); + restored['source'] = restoreSource; + restorePayload = jsonEncode(restored); await tx.update('sleep_nap', { 'source': restoreSource, 'created_at': DateTime.now().millisecondsSinceEpoch ~/ 1000, - 'payload_json': ?restorePayload, + 'payload_json': restorePayload, }, where: 'day_id = ? AND start_ts = ?', whereArgs: [dayId, startTs]); } else { await tx.delete('sleep_nap', where: 'day_id = ? AND start_ts = ?', whereArgs: [dayId, startTs]); diff --git a/pubspec.lock b/pubspec.lock index d7f845952..8d6d6b968 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -937,9 +937,9 @@ packages: dependency: "direct main" description: path: "." - ref: 77fe373eb819fda235f80610e898a4bc20a7a249 - resolved-ref: 77fe373eb819fda235f80610e898a4bc20a7a249 - url: "https://github.com/OpenStrap/analytics.git" + ref: "74165e45254203c5784ad88a53d8ec6ab099d6dd" + resolved-ref: "74165e45254203c5784ad88a53d8ec6ab099d6dd" + url: "https://github.com/DropTabl/analytics.git" source: git version: "1.0.0" openstrap_protocol: diff --git a/pubspec.yaml b/pubspec.yaml index 3501cd10e..3edec1730 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -265,7 +265,7 @@ dependencies: ref: 89080bcfac7767b3a871fd3a7d9307f5f30dad26 openstrap_analytics: git: - url: https://github.com/OpenStrap/analytics.git + url: https://github.com/DropTabl/analytics.git # analytics main @ #34 merge. Two hops in one: #32 (the HR-onset bypass # for low-limb-swing cardio) had already merged and this pin was still # sitting on its PR-branch head, and #34 lands the sleep-stager rewrite. @@ -512,7 +512,9 @@ dependencies: # analytics main @ 77fe373, the #95 merge (tree-identical to its head # 608c46f): readiness autonomic merge + spread calibration + capped # re-centring + robust lnRMSSD centre, for kAlgoVersion 112. - ref: 77fe373eb819fda235f80610e898a4bc20a7a249 + # Preserve interrupted main sleep with the detector's + # 90-minute continuation limit; awake/unobserved gaps stay excluded. + ref: 74165e45254203c5784ad88a53d8ec6ab099d6dd # BLE — flutter_blue_plus is the maintained cross-platform GATT client. flutter_blue_plus: ^1.36.8 diff --git a/test/accepted_naps_test.dart b/test/accepted_naps_test.dart new file mode 100644 index 000000000..73b1f82c0 --- /dev/null +++ b/test/accepted_naps_test.dart @@ -0,0 +1,79 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:openstrap_edge/compute/accepted_naps.dart'; +import 'package:openstrap_edge/compute/nap_edits.dart'; + +Map bundle({bool mainSleep = true}) => { + if (mainSleep) + 'sleep': { + 'window': { + 'value': {'onset_ms': 0, 'offset_ms': 8 * 3600 * 1000}, + }, + }, + 'naps': {'value': >[], 'assessment_complete': true}, + 'sleep_periods': { + 'assessment_complete': true, + 'periods': [ + if (mainSleep) {'is_main': true, 'duration_min': 360}, + ], + }, +}; + +NapEdit nap(int start, int end, {String source = 'legacy'}) => NapEdit( + kind: NapEditKind.added, + startSec: start, + endSec: end, + snapshot: source == 'manual' ? null : {'source': source, 'duration_min': 120}, +); + +void main() { + test('a legacy continuation is not also credited as a nap', () { + final day = bundle(); + final edit = nap(6 * 3600, 8 * 3600 + 30); + composeAcceptedNaps(day, [edit]); + + expect(day['naps']['value'], isEmpty); + expect(day['scalars']['nap_min'], 0); + expect(day['sleep_periods']['periods'], hasLength(1)); + expect(day['sleep_periods']['total_asleep_min'], 360); + composeAcceptedNaps(day, [edit]); + expect(day['scalars']['nap_min'], 0); + expect(day['sleep_periods']['total_asleep_min'], 360); + + // Keep the stored decision: a later correction that removes the main + // window can expose this original snapshot again. + final withoutMain = bundle(mainSleep: false); + composeAcceptedNaps(withoutMain, [edit]); + expect(withoutMain['naps']['value'], hasLength(1)); + expect(withoutMain['scalars']['nap_min'], 120); + }); + + test('legacy naps adjoining the main window stay separate', () { + final day = bundle(); + composeAcceptedNaps(day, [nap(-7200, 0), nap(8 * 3600, 10 * 3600)]); + expect(day['naps']['value'], hasLength(2)); + expect(day['scalars']['nap_min'], 240); + expect(day['sleep_periods']['total_asleep_min'], 600); + }); + + for (final window in [ + {}, + {'onset_ms': 1000, 'offset_ms': 0}, + {'onset_ms': 'unknown', 'offset_ms': 8 * 3600 * 1000}, + ]) { + test('invalid main window preserves the legacy nap: $window', () { + final day = bundle(); + day['sleep'] = {'window': {'value': window}}; + composeAcceptedNaps(day, [nap(6 * 3600, 8 * 3600)]); + expect(day['naps']['value'], hasLength(1)); + }); + } + + for (final source in ['manual', 'confirmed']) { + test('a corrected window preserves a $source nap decision', () { + final day = bundle(); + composeAcceptedNaps(day, [nap(6 * 3600, 8 * 3600, source: source)]); + expect(day['naps']['value'], hasLength(1)); + expect(day['scalars']['nap_min'], 120); + }); + } +} diff --git a/test/activity_review_regression_test.dart b/test/activity_review_regression_test.dart index c19f34d80..ceeb45ab6 100644 --- a/test/activity_review_regression_test.dart +++ b/test/activity_review_regression_test.dart @@ -484,7 +484,7 @@ void main() { expect(restored['confidence'], 0.7); expect( restored['source'], - source == 'confirmed' ? 'confirmed' : 'legacy', + 'confirmed', ); expect(await store.pending(), isEmpty); expect(await db.query('decoded_onehz'), isEmpty); @@ -513,7 +513,7 @@ void main() { (await LocalDb.dayResult(day))!['payload_json'] as String, ); final restored = (bundle['naps']['value'] as List).single as Map; - expect(restored['source'], 'legacy'); + expect(restored['source'], 'confirmed'); expect(restored['start'], start); expect(bundle['scalars']['nap_min'], 30); }); diff --git a/test/activity_review_test.dart b/test/activity_review_test.dart index fff563977..567704a0c 100644 --- a/test/activity_review_test.dart +++ b/test/activity_review_test.dart @@ -61,11 +61,13 @@ void main() { int? version, List naps = const [], String? source = 'band', + Map? mainWindow, }) async { await LocalDb.putDayResult( dayId: day, algoVersion: version ?? kAlgoVersion, payloadJson: jsonEncode({ + if (mainWindow != null) 'sleep': {'window': {'value': mainWindow}}, 'scalars': {'rhr': 53, 'readiness': 74, 'nap_min': 0}, 'naps': {'value': naps, 'count': naps.length}, 'sleep_periods': { @@ -492,6 +494,44 @@ void main() { expect(await store.pending(), isEmpty); }); + test('a corrected main window excludes a captured legacy nap on every write', () async { + await db.update('activity_review_meta', {'activated_at': now}); + await dayResult(version: kAlgoVersion - 1, naps: [nap()], source: null); + await dayResult(mainWindow: { + 'onset_ms': (start - 6 * 3600) * 1000, + 'offset_ms': (start + 3600) * 1000, + }); + Future check() async { + final saved = jsonDecode((await LocalDb.dayResult(day))!['payload_json'] as String); + expect(saved['naps']['value'], isEmpty); + expect(saved['scalars']['nap_min'], 0); + expect(saved['sleep_periods']['total_asleep_min'], 420); + expect((await LocalDb.metricSeries('nap_min')).single['value'], 0); + expect((await LocalDb.napEdits(day)).single['source'], 'legacy'); + } + await check(); + // The durable review path has no raw input and must compose identically. + await ActivityStore.markDayChanged(db, day); + await LocalDb.applyPendingActivityReviews(); + await check(); + }); + + test('putting a legacy nap back records an explicit confirmation', () async { + await db.update('activity_review_meta', {'activated_at': now}); + await dayResult(version: kAlgoVersion - 1, naps: [nap()], source: null); + await dayResult(mainWindow: { + 'onset_ms': (start - 6 * 3600) * 1000, + 'offset_ms': (start + 3600) * 1000, + }); + await LocalDb.putNapEdit(dayId: day, startTs: start, endTs: start + 1800, source: 'rejected'); + await LocalDb.deleteNapEdit(day, start); + await LocalDb.applyPendingActivityReviews(); + final saved = jsonDecode((await LocalDb.dayResult(day))!['payload_json'] as String); + expect((await LocalDb.napEdits(day)).single['source'], 'confirmed'); + expect(saved['naps']['value'], hasLength(1)); + expect(saved['scalars']['nap_min'], 24); + }); + test('older refresh cannot clear a newer durable review job', () async { final s = await detectNap(); await store.discard(s); diff --git a/test/fixtures/whoop_freeze/gen4_minus0400.json b/test/fixtures/whoop_freeze/gen4_minus0400.json index 82c4b8122..b061e3d97 100644 --- a/test/fixtures/whoop_freeze/gen4_minus0400.json +++ b/test/fixtures/whoop_freeze/gen4_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_plus0530.json b/test/fixtures/whoop_freeze/gen4_plus0530.json index 071bd2e28..5c3c33bfd 100644 --- a/test/fixtures/whoop_freeze/gen4_plus0530.json +++ b/test/fixtures/whoop_freeze/gen4_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_utc.json b/test/fixtures/whoop_freeze/gen4_utc.json index 985e1bd8f..7cc69a284 100644 --- a/test/fixtures/whoop_freeze/gen4_utc.json +++ b/test/fixtures/whoop_freeze/gen4_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_minus0400.json b/test/fixtures/whoop_freeze/gen5_minus0400.json index 6c4a2008d..5a25933af 100644 --- a/test/fixtures/whoop_freeze/gen5_minus0400.json +++ b/test/fixtures/whoop_freeze/gen5_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_plus0530.json b/test/fixtures/whoop_freeze/gen5_plus0530.json index 3109bf0c1..1cb02facd 100644 --- a/test/fixtures/whoop_freeze/gen5_plus0530.json +++ b/test/fixtures/whoop_freeze/gen5_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_utc.json b/test/fixtures/whoop_freeze/gen5_utc.json index 781e9ee03..fa75535ce 100644 --- a/test/fixtures/whoop_freeze/gen5_utc.json +++ b/test/fixtures/whoop_freeze/gen5_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 113, + "algo_version": 114, "payload_json": { "day_id": "2026-07-15", "active_min": 40, From b96cee527de36ee4818b04e4bed2581e0ab928bf Mon Sep 17 00:00:00 2001 From: Alex Wagner Date: Fri, 16 Oct 2026 19:30:38 +0200 Subject: [PATCH 02/10] fix: preserve partial legacy naps and cap grouped sleep --- lib/compute/accepted_naps.dart | 10 ++++--- lib/compute/derivation_engine.dart | 6 +++-- pubspec.lock | 8 +++--- pubspec.yaml | 5 +++- test/accepted_naps_test.dart | 27 +++++++++++++++++-- test/activity_review_test.dart | 21 +++++++++++++++ .../fixtures/whoop_freeze/gen4_minus0400.json | 18 ++++++------- test/fixtures/whoop_freeze/gen4_plus0530.json | 18 ++++++------- test/fixtures/whoop_freeze/gen4_utc.json | 18 ++++++------- .../fixtures/whoop_freeze/gen5_minus0400.json | 18 ++++++------- test/fixtures/whoop_freeze/gen5_plus0530.json | 18 ++++++------- test/fixtures/whoop_freeze/gen5_utc.json | 18 ++++++------- 12 files changed, 118 insertions(+), 67 deletions(-) diff --git a/lib/compute/accepted_naps.dart b/lib/compute/accepted_naps.dart index 1625a3094..3229ec665 100644 --- a/lib/compute/accepted_naps.dart +++ b/lib/compute/accepted_naps.dart @@ -17,15 +17,17 @@ void composeAcceptedNaps(Map bundle, List edits) { offset.isFinite && offset > onset; // A corrected main window can absorb an older detector's nap snapshot. - // Suppress that legacy overlap in every total, retaining the stored entry - // for a later window correction. Manual/confirmed decisions still win. + // Suppress only fully contained snapshots, retaining the stored entry for + // a later correction. Partial overlaps keep their recorded duration: the + // snapshot has no stages to apportion sleep inside/outside the main window. + // Manual/confirmed decisions still win. final accepted = applyNapEdits(const [], edits) .where( (nap) => nap['source'] != 'legacy' || !hasMainWindow || - (nap['end'] as num) * 1000 <= onset || - (nap['start'] as num) * 1000 >= offset, + (nap['start'] as num) * 1000 < onset || + (nap['end'] as num) * 1000 > offset, ) .toList(); // Whether the detector judged the day, persisted so a later compose cannot diff --git a/lib/compute/derivation_engine.dart b/lib/compute/derivation_engine.dart index 929fead53..22a517742 100644 --- a/lib/compute/derivation_engine.dart +++ b/lib/compute/derivation_engine.dart @@ -1815,7 +1815,9 @@ import 'vendor_sleep.dart'; // second sleep blocks after hour-long awakenings; gaps stay wake/unobserved. // Legacy nap snapshots overlapping the corrected main window no longer add // the same sleep twice. Explicit nap confirmations and restorations survive. -const int kAlgoVersion = 114; +// 114 → 115: cap grouped sleep at 16 hours and preserve legacy naps that +// only partially overlap the main window; only full containment is absorbed. +const int kAlgoVersion = 115; /// The sibling SHAs this version was derived against, asserted against /// pubspec.yaml in test/db_serve_version_and_reads_test.dart. /// @@ -2001,7 +2003,7 @@ const int kAlgoVersion = 114; // REPIN @ 77fe373: analytics main, #95 merge (readiness autonomic // merge + spread calibration + capped re-centring + robust lnRMSSD // centre), for v112. -const String kAnalyticsPin = '74165e45254203c5784ad88a53d8ec6ab099d6dd'; +const String kAnalyticsPin = '302332bbe74d82b9bd10d08f93f8a058a3108123'; // Repinned to analytics main's tip, which carries BOTH PR #72 (hrv_freq // Welch gap guard) and PR #73 (overreachingConjunction rhr quantum guard) — // the two independent kAlgoVersion bumps above (93 and 94). Verified both diff --git a/pubspec.lock b/pubspec.lock index 8d6d6b968..94cf5bae4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -937,8 +937,8 @@ packages: dependency: "direct main" description: path: "." - ref: "74165e45254203c5784ad88a53d8ec6ab099d6dd" - resolved-ref: "74165e45254203c5784ad88a53d8ec6ab099d6dd" + ref: "302332bbe74d82b9bd10d08f93f8a058a3108123" + resolved-ref: "302332bbe74d82b9bd10d08f93f8a058a3108123" url: "https://github.com/DropTabl/analytics.git" source: git version: "1.0.0" @@ -946,8 +946,8 @@ packages: dependency: "direct main" description: path: "." - ref: 89080bcfac7767b3a871fd3a7d9307f5f30dad26 - resolved-ref: 89080bcfac7767b3a871fd3a7d9307f5f30dad26 + ref: "89080bcfac7767b3a871fd3a7d9307f5f30dad26" + resolved-ref: "89080bcfac7767b3a871fd3a7d9307f5f30dad26" url: "https://github.com/OpenStrap/protocol.git" source: git version: "1.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3edec1730..86c8971b4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -265,6 +265,9 @@ dependencies: ref: 89080bcfac7767b3a871fd3a7d9307f5f30dad26 openstrap_analytics: git: + # Temporary reviewed pin for OpenStrap/analytics#96. Before release, + # restore the upstream URL and pin its merge SHA in all three locations: + # this ref, pubspec.lock, and kAnalyticsPin. url: https://github.com/DropTabl/analytics.git # analytics main @ #34 merge. Two hops in one: #32 (the HR-onset bypass # for low-limb-swing cardio) had already merged and this pin was still @@ -514,7 +517,7 @@ dependencies: # re-centring + robust lnRMSSD centre, for kAlgoVersion 112. # Preserve interrupted main sleep with the detector's # 90-minute continuation limit; awake/unobserved gaps stay excluded. - ref: 74165e45254203c5784ad88a53d8ec6ab099d6dd + ref: 302332bbe74d82b9bd10d08f93f8a058a3108123 # BLE — flutter_blue_plus is the maintained cross-platform GATT client. flutter_blue_plus: ^1.36.8 diff --git a/test/accepted_naps_test.dart b/test/accepted_naps_test.dart index 73b1f82c0..83ae32131 100644 --- a/test/accepted_naps_test.dart +++ b/test/accepted_naps_test.dart @@ -28,7 +28,7 @@ NapEdit nap(int start, int end, {String source = 'legacy'}) => NapEdit( void main() { test('a legacy continuation is not also credited as a nap', () { final day = bundle(); - final edit = nap(6 * 3600, 8 * 3600 + 30); + final edit = nap(6 * 3600, 8 * 3600); composeAcceptedNaps(day, [edit]); expect(day['naps']['value'], isEmpty); @@ -47,6 +47,27 @@ void main() { expect(withoutMain['scalars']['nap_min'], 120); }); + for (final bounds in [ + (-3600, 3600), + (7 * 3600, 9 * 3600), + (-3600, 9 * 3600), + ]) { + test( + 'a partially overlapping legacy nap keeps its recorded duration: $bounds', + () { + final day = bundle(); + final edit = nap(bounds.$1, bounds.$2); + composeAcceptedNaps(day, [edit]); + expect(day['naps']['value'], hasLength(1)); + expect(day['scalars']['nap_min'], 120); + expect(day['sleep_periods']['total_asleep_min'], 480); + composeAcceptedNaps(day, [edit]); + expect(day['scalars']['nap_min'], 120); + expect(day['sleep_periods']['total_asleep_min'], 480); + }, + ); + } + test('legacy naps adjoining the main window stay separate', () { final day = bundle(); composeAcceptedNaps(day, [nap(-7200, 0), nap(8 * 3600, 10 * 3600)]); @@ -62,7 +83,9 @@ void main() { ]) { test('invalid main window preserves the legacy nap: $window', () { final day = bundle(); - day['sleep'] = {'window': {'value': window}}; + day['sleep'] = { + 'window': {'value': window}, + }; composeAcceptedNaps(day, [nap(6 * 3600, 8 * 3600)]); expect(day['naps']['value'], hasLength(1)); }); diff --git a/test/activity_review_test.dart b/test/activity_review_test.dart index 567704a0c..7ba776ae5 100644 --- a/test/activity_review_test.dart +++ b/test/activity_review_test.dart @@ -516,6 +516,27 @@ void main() { await check(); }); + test('a partially overlapping captured nap survives persistence and review', () async { + await db.update('activity_review_meta', {'activated_at': now}); + await dayResult(version: kAlgoVersion - 1, naps: [nap()], source: null); + await dayResult(mainWindow: { + 'onset_ms': (start - 6 * 3600) * 1000, + 'offset_ms': (start + 900) * 1000, + }); + Future check() async { + final saved = jsonDecode((await LocalDb.dayResult(day))!['payload_json'] as String); + expect(saved['naps']['value'], hasLength(1)); + expect(saved['scalars']['nap_min'], 24); + expect(saved['sleep_periods']['total_asleep_min'], 444); + expect((await LocalDb.metricSeries('nap_min')).single['value'], 24); + expect((await LocalDb.napEdits(day)).single['source'], 'legacy'); + } + await check(); + await ActivityStore.markDayChanged(db, day); + await LocalDb.applyPendingActivityReviews(); + await check(); + }); + test('putting a legacy nap back records an explicit confirmation', () async { await db.update('activity_review_meta', {'activated_at': now}); await dayResult(version: kAlgoVersion - 1, naps: [nap()], source: null); diff --git a/test/fixtures/whoop_freeze/gen4_minus0400.json b/test/fixtures/whoop_freeze/gen4_minus0400.json index b061e3d97..d16459411 100644 --- a/test/fixtures/whoop_freeze/gen4_minus0400.json +++ b/test/fixtures/whoop_freeze/gen4_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_plus0530.json b/test/fixtures/whoop_freeze/gen4_plus0530.json index 5c3c33bfd..31416877c 100644 --- a/test/fixtures/whoop_freeze/gen4_plus0530.json +++ b/test/fixtures/whoop_freeze/gen4_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_utc.json b/test/fixtures/whoop_freeze/gen4_utc.json index 7cc69a284..17a866510 100644 --- a/test/fixtures/whoop_freeze/gen4_utc.json +++ b/test/fixtures/whoop_freeze/gen4_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_minus0400.json b/test/fixtures/whoop_freeze/gen5_minus0400.json index 5a25933af..305786e80 100644 --- a/test/fixtures/whoop_freeze/gen5_minus0400.json +++ b/test/fixtures/whoop_freeze/gen5_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_plus0530.json b/test/fixtures/whoop_freeze/gen5_plus0530.json index 1cb02facd..e53da5827 100644 --- a/test/fixtures/whoop_freeze/gen5_plus0530.json +++ b/test/fixtures/whoop_freeze/gen5_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_utc.json b/test/fixtures/whoop_freeze/gen5_utc.json index fa75535ce..5531fbc1a 100644 --- a/test/fixtures/whoop_freeze/gen5_utc.json +++ b/test/fixtures/whoop_freeze/gen5_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 114, + "algo_version": 115, "payload_json": { "day_id": "2026-07-15", "active_min": 40, From 39809df7ee5aedd9d02b6e7c2afc969aab8874cf Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 18:40:13 +0530 Subject: [PATCH 03/10] repin analytics to main and restamp the freeze snapshots at v117 the fork pin is replaced by analytics main, which carries the same sleep continuation change. the snapshots move only where the new pin changes output: version stamp, prsa tier/note, one readiness band. --- .../fixtures/whoop_freeze/gen4_minus0400.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen4_plus0530.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen4_utc.json | 68 +++++++++---------- .../fixtures/whoop_freeze/gen5_minus0400.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen5_plus0530.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen5_utc.json | 68 +++++++++---------- 6 files changed, 204 insertions(+), 204 deletions(-) diff --git a/test/fixtures/whoop_freeze/gen4_minus0400.json b/test/fixtures/whoop_freeze/gen4_minus0400.json index 2509c77ca..16d93bd94 100644 --- a/test/fixtures/whoop_freeze/gen4_minus0400.json +++ b/test/fixtures/whoop_freeze/gen4_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "suppressed", + "band": "normal", "saturation_flag": false }, "confidence": 0.9, @@ -24898,11 +24898,11 @@ "readiness": 27.033995461954163, "skipped": 0, "partial": 0, - "payload_sha256": "8c4970c794a3f8bb5664ac877d4bf0657d85be516c6a692b9855bf54afeb92a8" + "payload_sha256": "b57127eaba2e220875324219ed002d3801c330506d1303b87a413572f89ec560" }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25048,11 +25048,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -25061,11 +25061,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -49126,7 +49126,7 @@ "naps": { "value": [ { - "start": 1784050199, + "start": 1784050203, "end": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49158,7 +49158,7 @@ }, { "is_main": false, - "onset_ts": 1784050199, + "onset_ts": 1784050203, "wake_ts": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49591,11 +49591,11 @@ "readiness": 27.03409387728019, "skipped": 0, "partial": 0, - "payload_sha256": "e61aa65ce319b6077929d91d99aed2e111db9d82efc10a812a017e422838a3dc" + "payload_sha256": "3f4838375946c33e26860d81e49abfb0e7fc17b0087cbac28f3bcb1db8c3b89d" }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -49741,11 +49741,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -49754,11 +49754,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -72717,7 +72717,7 @@ "readiness": 66.11544177079463, "skipped": 0, "partial": 0, - "payload_sha256": "1b08d706da4deab1241c94434834c01d27feb0a4bc00857027c25f42f5808375" + "payload_sha256": "eb9d15f24b218b7d4438e5a6504f33efc6a924f513657215fc436bae3d563fb7" } ], "metric_series": [ @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -76923,17 +76923,17 @@ "linked_id": null }, { - "id": "nap:1784050199", + "id": "nap:1784050203", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784050199, + "start_ts": 1784050203, "end_ts": 1784052901, - "detection_start": 1784050199, + "detection_start": 1784050203, "detection_end": 1784052901, - "details_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784050199" + "linked_id": "2026-07-14:1784050203" }, { "id": "2026-07-15:1784151128", @@ -76978,10 +76978,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784050199, + "start_ts": 1784050203, "end_ts": 1784052901, "source": "confirmed", - "payload_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen4_plus0530.json b/test/fixtures/whoop_freeze/gen4_plus0530.json index 4f489c854..928411ce5 100644 --- a/test/fixtures/whoop_freeze/gen4_plus0530.json +++ b/test/fixtures/whoop_freeze/gen4_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "suppressed", + "band": "normal", "saturation_flag": false }, "confidence": 0.9, @@ -24898,11 +24898,11 @@ "readiness": 27.03382323567632, "skipped": 0, "partial": 0, - "payload_sha256": "6af3a3dd03487fb00e59cee8fc3b80d13d8b3df613625f0e53e6b354b3beacae" + "payload_sha256": "cda75458f39702ac4580c5d03d4bf6a6b5c5120aee516e8c32d1c6fe33383def" }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25048,11 +25048,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -25061,11 +25061,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -49126,7 +49126,7 @@ "naps": { "value": [ { - "start": 1784015998, + "start": 1784016002, "end": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49158,7 +49158,7 @@ }, { "is_main": false, - "onset_ts": 1784015998, + "onset_ts": 1784016002, "wake_ts": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49591,11 +49591,11 @@ "readiness": 27.033601802905416, "skipped": 0, "partial": 0, - "payload_sha256": "1a10d8277390720929818867fe39e2a3ae139149d0d93057c2ca4f1776cae03b" + "payload_sha256": "3228493c5545d3a4ee5f2da9410317da44cf8e9947d17b049572ca698c63112d" }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -49741,11 +49741,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -49754,11 +49754,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -72717,7 +72717,7 @@ "readiness": 66.1155535435143, "skipped": 0, "partial": 0, - "payload_sha256": "180be6438701ff7edef6abd47022db857f820e5821842d48daad59504205106f" + "payload_sha256": "0187cd292873351886d856d95ba367289227f875a585b0bbbee6c5525617a6da" } ], "metric_series": [ @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -76923,17 +76923,17 @@ "linked_id": null }, { - "id": "nap:1784015998", + "id": "nap:1784016002", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784015998, + "start_ts": 1784016002, "end_ts": 1784018701, - "detection_start": 1784015998, + "detection_start": 1784016002, "detection_end": 1784018701, - "details_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784015998" + "linked_id": "2026-07-14:1784016002" }, { "id": "2026-07-15:1784116928", @@ -76978,10 +76978,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784015998, + "start_ts": 1784016002, "end_ts": 1784018701, "source": "confirmed", - "payload_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen4_utc.json b/test/fixtures/whoop_freeze/gen4_utc.json index 080f8e0ad..8627a4f89 100644 --- a/test/fixtures/whoop_freeze/gen4_utc.json +++ b/test/fixtures/whoop_freeze/gen4_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "suppressed", + "band": "normal", "saturation_flag": false }, "confidence": 0.9, @@ -24898,11 +24898,11 @@ "readiness": 27.03355259577805, "skipped": 0, "partial": 0, - "payload_sha256": "3e26efc18e699e2f58ece9a0e85a82907b9f0fab3816fdd3c37d2f94353d3f9b" + "payload_sha256": "f13bcc5af9185bb1b8384a9bc439a551a03bc4367ea2fba85c5742ef910df9d8" }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25048,11 +25048,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -25061,11 +25061,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -49126,7 +49126,7 @@ "naps": { "value": [ { - "start": 1784035800, + "start": 1784035804, "end": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49158,7 +49158,7 @@ }, { "is_main": false, - "onset_ts": 1784035800, + "onset_ts": 1784035804, "wake_ts": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49591,11 +49591,11 @@ "readiness": 27.033651010089166, "skipped": 0, "partial": 0, - "payload_sha256": "6aa01c2a1822f99c76ac72f5d48c790b012350d756d6d634761d6c3391bbf2a8" + "payload_sha256": "411649f61ac1083a68de60dd1ff589276d011a075e7d22d81f88d4a692c5346a" }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -49741,11 +49741,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -49754,11 +49754,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -72717,7 +72717,7 @@ "readiness": 66.11559080104756, "skipped": 0, "partial": 0, - "payload_sha256": "eb87bade45c3cb62e08cf93cfced5112d7de421c1b54917e24403c9288eb2e12" + "payload_sha256": "26aef4d4f03d8744be1225adb85776a659769af4bd0c02091696b58efd7e48fe" } ], "metric_series": [ @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -76923,17 +76923,17 @@ "linked_id": null }, { - "id": "nap:1784035800", + "id": "nap:1784035804", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784035800, + "start_ts": 1784035804, "end_ts": 1784038502, - "detection_start": 1784035800, + "detection_start": 1784035804, "detection_end": 1784038502, - "details_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784035800" + "linked_id": "2026-07-14:1784035804" }, { "id": "2026-07-15:1784136728", @@ -76978,10 +76978,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784035800, + "start_ts": 1784035804, "end_ts": 1784038502, "source": "confirmed", - "payload_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen5_minus0400.json b/test/fixtures/whoop_freeze/gen5_minus0400.json index c1752aa1d..0c226d0f9 100644 --- a/test/fixtures/whoop_freeze/gen5_minus0400.json +++ b/test/fixtures/whoop_freeze/gen5_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "suppressed", + "band": "normal", "saturation_flag": false }, "confidence": 0.9, @@ -25076,11 +25076,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "d11bcb420276e13e38219499ddd2158c7a0ded41bcd103f4a82b0999296363e1" + "payload_sha256": "a3f73d5823f32766fd6f8741f46e2a72ac064ea73b044321b9ebb50480b75058" }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25226,11 +25226,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -25239,11 +25239,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -49477,7 +49477,7 @@ "naps": { "value": [ { - "start": 1784050199, + "start": 1784050203, "end": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49509,7 +49509,7 @@ }, { "is_main": false, - "onset_ts": 1784050199, + "onset_ts": 1784050203, "wake_ts": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49942,11 +49942,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "1f75b2b3f4d709b60f33261cb89dbddcfb09a714912de305780e481ed9dd91be" + "payload_sha256": "9cc78bf91ecb2c555fe49878acefe1b2eea8f2e8b6746d742c03f8287350fcaa" }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -50092,11 +50092,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -50105,11 +50105,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -73230,7 +73230,7 @@ "readiness": 61.79377627786914, "skipped": 0, "partial": 0, - "payload_sha256": "3e6d6de8482792a8bc10c95274ccada375153d5d4cff0de81562a61c0ec371f7" + "payload_sha256": "e8a33133f77bf08bec2c0293cf63f699c19f63a18ad915ec4228cc244786d195" } ], "metric_series": [ @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -77436,17 +77436,17 @@ "linked_id": null }, { - "id": "nap:1784050199", + "id": "nap:1784050203", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784050199, + "start_ts": 1784050203, "end_ts": 1784052901, - "detection_start": 1784050199, + "detection_start": 1784050203, "detection_end": 1784052901, - "details_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784050199" + "linked_id": "2026-07-14:1784050203" }, { "id": "2026-07-15:1784151134", @@ -77491,10 +77491,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784050199, + "start_ts": 1784050203, "end_ts": 1784052901, "source": "confirmed", - "payload_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen5_plus0530.json b/test/fixtures/whoop_freeze/gen5_plus0530.json index 05bb93f35..612a5dd00 100644 --- a/test/fixtures/whoop_freeze/gen5_plus0530.json +++ b/test/fixtures/whoop_freeze/gen5_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "suppressed", + "band": "normal", "saturation_flag": false }, "confidence": 0.9, @@ -25076,11 +25076,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "123df037199b6fbdfe0cb1298838389c45534d672ba2df685d019a3e2b93e047" + "payload_sha256": "a6bb812440c40efd53dc915e78474d6581b354a787fd83f1d8d82274e94b052b" }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25226,11 +25226,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -25239,11 +25239,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -49477,7 +49477,7 @@ "naps": { "value": [ { - "start": 1784015998, + "start": 1784016002, "end": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49509,7 +49509,7 @@ }, { "is_main": false, - "onset_ts": 1784015998, + "onset_ts": 1784016002, "wake_ts": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49942,11 +49942,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "56e0e7b112441f73b1849430ffdf15fb10beeced9ef19d505ffb9359afb45262" + "payload_sha256": "e6ee25535499c542ebd13b8a1df85566c229944efba4dbdb8a44ca980c6442dc" }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -50092,11 +50092,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -50105,11 +50105,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -73230,7 +73230,7 @@ "readiness": 61.79377627786914, "skipped": 0, "partial": 0, - "payload_sha256": "3d0fc39b9ecb2646dec22203f8d82e2b3b035486921a383e012bdca3a8a6fb9f" + "payload_sha256": "0ba224b91e74c386567f55d2b31b8346e4601bd61161202740d4bd0a7fa97f2c" } ], "metric_series": [ @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -77436,17 +77436,17 @@ "linked_id": null }, { - "id": "nap:1784015998", + "id": "nap:1784016002", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784015998, + "start_ts": 1784016002, "end_ts": 1784018701, - "detection_start": 1784015998, + "detection_start": 1784016002, "detection_end": 1784018701, - "details_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784015998" + "linked_id": "2026-07-14:1784016002" }, { "id": "2026-07-15:1784116934", @@ -77491,10 +77491,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784015998, + "start_ts": 1784016002, "end_ts": 1784018701, "source": "confirmed", - "payload_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen5_utc.json b/test/fixtures/whoop_freeze/gen5_utc.json index f09f6882b..909c35e0f 100644 --- a/test/fixtures/whoop_freeze/gen5_utc.json +++ b/test/fixtures/whoop_freeze/gen5_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "suppressed", + "band": "normal", "saturation_flag": false }, "confidence": 0.9, @@ -25076,11 +25076,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "1dc0892666ef22d6728bd2329f6bda7eacbe551676ce6c1b623df833b5e5bd9b" + "payload_sha256": "64bd6e2d3cd9fb8a3762d32513c756dbfe5d33e204538d64f6188eb88b25afff" }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25226,11 +25226,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -25239,11 +25239,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -49477,7 +49477,7 @@ "naps": { "value": [ { - "start": 1784035800, + "start": 1784035804, "end": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49509,7 +49509,7 @@ }, { "is_main": false, - "onset_ts": 1784035800, + "onset_ts": 1784035804, "wake_ts": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49942,11 +49942,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "e82f76c2d4cd34faf73db2fa0f439fe79a9d1442f0862c3bd711d5b14e436d40" + "payload_sha256": "42d874e0691a2e1f19f3ca870dbf497fd820f6daa556da8bec1cbc7f62b661ca" }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -50092,11 +50092,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" }, "prsa_ac": { "value": { @@ -50105,11 +50105,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "HIGH", + "tier": "RELATIVE", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" + "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" }, "readiness_lnrmssd": { "value": { @@ -73230,7 +73230,7 @@ "readiness": 61.79377627786914, "skipped": 0, "partial": 0, - "payload_sha256": "99f2bd90847f90067a05a6e034c5e248bbd84a45ee0b7e515ab6074556bb8a44" + "payload_sha256": "a63132ca185866d1519d888273fa38ecc42d26e091cdb18f4a5ba41823294b6c" } ], "metric_series": [ @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -77436,17 +77436,17 @@ "linked_id": null }, { - "id": "nap:1784035800", + "id": "nap:1784035804", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784035800, + "start_ts": 1784035804, "end_ts": 1784038502, - "detection_start": 1784035800, + "detection_start": 1784035804, "detection_end": 1784038502, - "details_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784035800" + "linked_id": "2026-07-14:1784035804" }, { "id": "2026-07-15:1784136734", @@ -77491,10 +77491,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784035800, + "start_ts": 1784035804, "end_ts": 1784038502, "source": "confirmed", - "payload_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ From dfcb5073d641afbd9d00bb42dd954608e64d38f4 Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 18:42:40 +0530 Subject: [PATCH 04/10] say so when there are too few older nights to compare heart-rate cycling the new analytics pin leaves the comparison empty until there are enough older nights. the screen read that as "stayed inside your range". --- lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 4 ++++ lib/l10n/app_es.arb | 1 + lib/l10n/app_fr.arb | 1 + lib/l10n/app_hi.arb | 1 + lib/l10n/app_ru.arb | 2 ++ lib/l10n/app_zh.arb | 1 + lib/ui2/screens/investigate.dart | 8 +++++++- test/ui2_wiring_r2_test.dart | 11 +++++++++++ 9 files changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index e8ad5b170..c0ea039be 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1049,6 +1049,7 @@ "investigateDroppedThin": "{count, plural, one{# Nacht wegen zu weniger beobachteter Stunden ausgelassen} other{# Nächte wegen zu weniger beobachteter Stunden ausgelassen}}", "investigateAcrossNOwnNights": "ÜBER {n} DEINER EIGENEN NÄCHTE", "investigateCvhrAboveUsual": "In deinen letzten Nächten lagen die Herzfrequenzzyklen, die diese Prüfung zählt, höher als in den {n} Nächten davor.", + "investigateCvhrNoComparisonYet": "Es gibt noch nicht genug frühere Nächte, um deine letzten Herzfrequenzzyklen damit zu vergleichen.", "investigateCvhrInsideUsual": "In deinen letzten Nächten lagen die Herzfrequenzzyklen, die diese Prüfung zählt, im Bereich der {n} Nächte davor.", "investigateCvhrExplainer": "Das ist ein Muster in deinem Puls, keine Messung deiner Atmung und kein Test auf irgendetwas. Dieselben Zyklen entstehen auch durch einen unregelmäßigen Herzrhythmus, durch Aufenthalte in der Höhe und durch jede unterbrochene Nacht – und Betablocker, Diabetes oder Nervenerkrankungen dämpfen sie, sodass eine tatsächlich gestörte Atmung hier oft gar keine Spur hinterlässt.", "investigateCvhrNotNegativeResult": "Nichts hier ist also ein negatives Ergebnis, nichts gibt Entwarnung, und nichts davon sagt etwas über eine einzelne Nacht aus – der Wert einer einzelnen Nacht schwankt schon aus einem Dutzend Gründen.", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3e09adf20..1ba978959 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -5016,6 +5016,10 @@ } } }, + "investigateCvhrNoComparisonYet": "There aren't enough earlier nights yet to compare your recent heart-rate cycling against.", + "@investigateCvhrNoComparisonYet": { + "description": "Sentence: too few older nights to say whether recent heart-rate cycling is above or inside the user's usual range" + }, "investigateCvhrInsideUsual": "Over your most recent nights, the heart-rate cycling this screen counts has stayed inside the range of the {n} nights behind it.", "@investigateCvhrInsideUsual": { "description": "Sentence: recent heart-rate cycling has stayed within the user's own usual range", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 4d2118ed2..de4e02584 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1020,6 +1020,7 @@ "investigateDroppedThin": "{count, plural, one{# noche excluida por muy pocas horas observadas} other{# noches excluidas por muy pocas horas observadas}}", "investigateAcrossNOwnNights": "EN {n} DE TUS PROPIAS NOCHES", "investigateCvhrAboveUsual": "En tus noches más recientes, el ciclo de frecuencia cardíaca que mide esta detección ha estado más alto que en las {n} noches que lo respaldan.", + "investigateCvhrNoComparisonYet": "Todavía no hay suficientes noches anteriores para comparar con ellas tu ciclo de frecuencia cardíaca reciente.", "investigateCvhrInsideUsual": "En tus noches más recientes, el ciclo de frecuencia cardíaca que mide esta detección se ha mantenido dentro del rango de las {n} noches que lo respaldan.", "investigateCvhrExplainer": "Es un patrón en tu pulso, no una medición de tu respiración, y no es una prueba de nada. El mismo ciclo se produce por un ritmo irregular, por estar en altitud y por cualquier noche entrecortada — y los betabloqueantes, la diabetes y los trastornos nerviosos lo atenúan, por lo que una respiración realmente alterada muchas veces no deja ninguna huella aquí.", "investigateCvhrNotNegativeResult": "Así que nada de esto es un resultado negativo ni descarta nada, y ninguno de estos datos dice nada sobre una noche en particular — el conteo de una sola noche cambia por docenas de razones por sí solo.", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index d30c7c634..478d663ea 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1020,6 +1020,7 @@ "investigateDroppedThin": "{count, plural, one{# nuit exclue pour trop peu d'heures observées} other{# nuits exclues pour trop peu d'heures observées}}", "investigateAcrossNOwnNights": "SUR {n} DE VOS PROPRES NUITS", "investigateCvhrAboveUsual": "Au cours de vos nuits les plus récentes, le cycle de fréquence cardiaque mesuré par ce dépistage a été plus élevé que sur les {n} nuits qui le composent.", + "investigateCvhrNoComparisonYet": "Il n'y a pas encore assez de nuits antérieures pour y comparer votre cycle de fréquence cardiaque récent.", "investigateCvhrInsideUsual": "Au cours de vos nuits les plus récentes, le cycle de fréquence cardiaque mesuré par ce dépistage est resté dans la plage des {n} nuits qui le composent.", "investigateCvhrExplainer": "C'est un motif dans votre pouls, pas une mesure de votre respiration, et ce n'est un test de rien. Le même cycle provient d'un rythme irrégulier, de l'altitude, ou de toute nuit entrecoupée — et les bêtabloquants, le diabète et les troubles nerveux l'atténuent, si bien qu'une respiration réellement perturbée ne laisse souvent aucune trace ici.", "investigateCvhrNotNegativeResult": "Rien ici n'est donc un résultat négatif et rien ici ne blanchit quoi que ce soit, et rien de tout cela ne dit quoi que ce soit sur une nuit en particulier — le compte d'une seule nuit varie pour une dizaine de raisons à lui seul.", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 89f1e08a4..cb955d1c6 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -1020,6 +1020,7 @@ "investigateDroppedThin": "बहुत कम प्रेक्षित घंटों के कारण {count} रातें बाहर रखी गईं", "investigateAcrossNOwnNights": "आपकी अपनी {n} रातों में", "investigateCvhrAboveUsual": "आपकी हाल की रातों में, इस स्क्रीन द्वारा गिनी गई हृदय-गति साइकलिंग इसके पीछे की {n} रातों के मुक़ाबले अधिक रही है।", + "investigateCvhrNoComparisonYet": "अभी इतनी पुरानी रातें नहीं हैं कि आपकी हाल की हृदय-गति साइकलिंग की उनसे तुलना की जा सके।", "investigateCvhrInsideUsual": "आपकी हाल की रातों में, इस स्क्रीन द्वारा गिनी गई हृदय-गति साइकलिंग इसके पीछे की {n} रातों की सीमा के भीतर बनी रही है।", "investigateCvhrExplainer": "यह आपकी पल्स में एक पैटर्न है, आपकी श्वास का माप नहीं, और यह किसी चीज़ की जाँच नहीं है। यही साइकलिंग अनियमित लय, ऊँचाई पर होने, या किसी भी टूटी हुई रात से आती है — और बीटा-ब्लॉकर्स, डायबिटीज़ और नर्व की स्थितियाँ इसे कम कर देती हैं, इसलिए वास्तव में बिगड़ी हुई श्वास अक्सर यहाँ कोई निशान नहीं छोड़ती।", "investigateCvhrNotNegativeResult": "इसलिए यहाँ कुछ भी नकारात्मक परिणाम नहीं है और यहाँ कुछ भी किसी चीज़ को साफ़ नहीं करता, और इनमें से कोई भी किसी एक रात के बारे में कुछ नहीं कहता — एक अकेली रात की गिनती अपने आप दर्जनों कारणों से बदलती है।", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 9010da858..424a746a0 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -2156,6 +2156,8 @@ } } }, + "investigateCvhrNoComparisonYet": "Пока недостаточно прежних ночей, чтобы сравнить с ними недавние циклические изменения пульса.", + "@investigateCvhrNoComparisonYet": {}, "investigateCvhrInsideUsual": "В последних ночах число циклических изменений пульса, которые учитывает проверка, остаётся в диапазоне предшествующих {n} ночей.", "@investigateCvhrInsideUsual": { "placeholders": { diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 858d2a12d..2b510a008 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1020,6 +1020,7 @@ "investigateDroppedThin": "因观测时长过短而排除 {count} 晚", "investigateAcrossNOwnNights": "基于你自己的 {n} 个夜晚", "investigateCvhrAboveUsual": "在你最近的几个夜晚中,本项筛查所计的心率周期水平高于其背后 {n} 个夜晚的整体水平。", + "investigateCvhrNoComparisonYet": "目前还没有足够多的早前夜晚,可用来与你最近的心率周期水平作比较。", "investigateCvhrInsideUsual": "在你最近的几个夜晚中,本项筛查所计的心率周期水平一直保持在其背后 {n} 个夜晚的范围之内。", "investigateCvhrExplainer": "这是脉搏中的一种模式,不是对呼吸的测量,也不是任何疾病的检测。同样的周期性变化可能来自心律不齐、身处高海拔,或任何断续的夜晚——而 β 受体阻滞剂、糖尿病和神经系统疾病会削弱这种信号,因此真正的呼吸紊乱往往在这里完全不留痕迹。", "investigateCvhrNotNegativeResult": "所以这里的一切都不构成阴性结果,也不能排除任何情况,其中任何一项都不能说明某一个具体夜晚的情况——单单一个夜晚的计数本身就会因十几种原因而波动。", diff --git a/lib/ui2/screens/investigate.dart b/lib/ui2/screens/investigate.dart index 8af6f8c39..58e96be5d 100644 --- a/lib/ui2/screens/investigate.dart +++ b/lib/ui2/screens/investigate.dart @@ -940,7 +940,13 @@ class _InvestigateState extends State { style: F.over.copyWith(color: p.ink3)), const SizedBox(height: S.x3), Text( - v.aboveOwnUsual + // Null until there are enough older nights to compare against; + // reading that as "inside your range" would hide a real jump. + v.aboveOwnUsual == null + ? (l?.investigateCvhrNoComparisonYet ?? + "There aren't enough earlier nights yet to compare your " + 'recent heart-rate cycling against.') + : v.aboveOwnUsual! ? (l?.investigateCvhrAboveUsual(n) ?? 'Over your most recent nights, the heart-rate cycling ' 'this screen counts has been running higher than ' diff --git a/test/ui2_wiring_r2_test.dart b/test/ui2_wiring_r2_test.dart index cf3f5163e..e054cfd20 100644 --- a/test/ui2_wiring_r2_test.dart +++ b/test/ui2_wiring_r2_test.dart @@ -1285,6 +1285,17 @@ void main() { findsOneWidget); }); + testWidgets('too few older nights makes no comparison either way', + (t) async { + final m = ana.cvhrPersonalDistribution(nights(6, recent: 3)); + expect(m.value?.aboveOwnUsual, isNull); + await pumpI(t, m); + expect(find.textContaining("aren't enough earlier nights"), + findsOneWidget); + expect(find.textContaining('running higher'), findsNothing); + expect(find.textContaining('stayed inside'), findsNothing); + }); + testWidgets('too few nights says so instead of showing a partial one', (t) async { await pumpI(t, ana.cvhrPersonalDistribution(nights(3))); From e47262aff4a5b12a609d79ebf2b780f8216e4c7a Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 18:49:22 +0530 Subject: [PATCH 05/10] update two fixtures for the new analytics pin the regularity score now needs half a day observed on adjacent days, so the midnight-wrap fixture uses a long night; a still block within an hour of the night now chains into it, so the lie-in is no longer a nap candidate. --- test/crossday_pipeline_test.dart | 18 ++++++++++++------ test/sleep_band_trim_wiring_test.dart | 12 ++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/test/crossday_pipeline_test.dart b/test/crossday_pipeline_test.dart index 758e2e978..226d85d33 100644 --- a/test/crossday_pipeline_test.dart +++ b/test/crossday_pipeline_test.dart @@ -192,9 +192,14 @@ void main() { // computed with a hole right at the boundary. test('a hypnogram segment crossing local midnight is not dropped from the ' 'SRI grid', () { - // Local 23:30 → 00:30 the next day, expressed as epoch seconds. - final onset = DateTime(2024, 3, 4, 23, 30).millisecondsSinceEpoch ~/ 1000; - final wake = DateTime(2024, 3, 5, 0, 30).millisecondsSinceEpoch ~/ 1000; + // Local 18:00 → 07:00 the next day, expressed as epoch seconds. Long + // enough that each adjacent-day pair clears the SRI's half-day coverage + // floor; a one-hour night is abstained on whether or not it wraps. + final onset = DateTime(2024, 3, 4, 18).millisecondsSinceEpoch ~/ 1000; + final wake = DateTime(2024, 3, 5, 7).millisecondsSinceEpoch ~/ 1000; + // The same span shifted to sit inside one calendar day: 00:30 → 13:30. + final sameStart = + DateTime(2024, 3, 5, 0, 30).millisecondsSinceEpoch ~/ 1000; List> nights({required bool crossMidnight}) => [ for (var i = 0; i < 14; i++) @@ -202,11 +207,12 @@ void main() { 'date': '2024-03-${(4 + i).toString().padLeft(2, '0')}', 'onset_sec': onset + i * 86400, 'wake_sec': wake + i * 86400, - 'tst_min': 60, + 'tst_min': 780, 'hypnogram': [ { - 'start': onset + i * 86400, - 'end': (crossMidnight ? wake : onset + 1800) + i * 86400, + 'start': (crossMidnight ? onset : sameStart) + i * 86400, + 'end': (crossMidnight ? wake : sameStart + 13 * 3600) + + i * 86400, 'stage': 'nrem', }, ], diff --git a/test/sleep_band_trim_wiring_test.dart b/test/sleep_band_trim_wiring_test.dart index d6b42a377..57fce5304 100644 --- a/test/sleep_band_trim_wiring_test.dart +++ b/test/sleep_band_trim_wiring_test.dart @@ -268,15 +268,19 @@ void main() { final napStart = _local(2025, 6, 16, 7, 30); - test('control: excluding only up to the trimmed wake emits the nap', () { + // The lie-in starts 20 minutes after the trimmed wake. The nap detector + // now chains any still block within an hour of the main sleep into the + // night, so it is not a nap candidate even when only the trimmed span is + // excluded. The exclusion below stays as the second line of defence. + test('the detector itself chains the lie-in into the night', () { final out = naps(_lieTrimmed); expect(out, isNotNull); expect( - out!.any((n) => + out!.where((n) => (n['start'] as int) >= napStart - 120 && (n['start'] as int) <= napStart + 300), - isTrue, - reason: 'the fixture must create a nap candidate: $out', + isEmpty, + reason: 'a still block 20 min after the night is not a nap: $out', ); }); From ec6d916b3fa3c27821af1547822250ba2f317635 Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 19:08:22 +0530 Subject: [PATCH 06/10] Revert "say so when there are too few older nights to compare heart-rate cycling" This reverts commit dfcb5073d641afbd9d00bb42dd954608e64d38f4. --- lib/l10n/app_de.arb | 1 - lib/l10n/app_en.arb | 4 ---- lib/l10n/app_es.arb | 1 - lib/l10n/app_fr.arb | 1 - lib/l10n/app_hi.arb | 1 - lib/l10n/app_ru.arb | 2 -- lib/l10n/app_zh.arb | 1 - lib/ui2/screens/investigate.dart | 8 +------- test/ui2_wiring_r2_test.dart | 11 ----------- 9 files changed, 1 insertion(+), 29 deletions(-) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index c0ea039be..e8ad5b170 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1049,7 +1049,6 @@ "investigateDroppedThin": "{count, plural, one{# Nacht wegen zu weniger beobachteter Stunden ausgelassen} other{# Nächte wegen zu weniger beobachteter Stunden ausgelassen}}", "investigateAcrossNOwnNights": "ÜBER {n} DEINER EIGENEN NÄCHTE", "investigateCvhrAboveUsual": "In deinen letzten Nächten lagen die Herzfrequenzzyklen, die diese Prüfung zählt, höher als in den {n} Nächten davor.", - "investigateCvhrNoComparisonYet": "Es gibt noch nicht genug frühere Nächte, um deine letzten Herzfrequenzzyklen damit zu vergleichen.", "investigateCvhrInsideUsual": "In deinen letzten Nächten lagen die Herzfrequenzzyklen, die diese Prüfung zählt, im Bereich der {n} Nächte davor.", "investigateCvhrExplainer": "Das ist ein Muster in deinem Puls, keine Messung deiner Atmung und kein Test auf irgendetwas. Dieselben Zyklen entstehen auch durch einen unregelmäßigen Herzrhythmus, durch Aufenthalte in der Höhe und durch jede unterbrochene Nacht – und Betablocker, Diabetes oder Nervenerkrankungen dämpfen sie, sodass eine tatsächlich gestörte Atmung hier oft gar keine Spur hinterlässt.", "investigateCvhrNotNegativeResult": "Nichts hier ist also ein negatives Ergebnis, nichts gibt Entwarnung, und nichts davon sagt etwas über eine einzelne Nacht aus – der Wert einer einzelnen Nacht schwankt schon aus einem Dutzend Gründen.", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 1ba978959..3e09adf20 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -5016,10 +5016,6 @@ } } }, - "investigateCvhrNoComparisonYet": "There aren't enough earlier nights yet to compare your recent heart-rate cycling against.", - "@investigateCvhrNoComparisonYet": { - "description": "Sentence: too few older nights to say whether recent heart-rate cycling is above or inside the user's usual range" - }, "investigateCvhrInsideUsual": "Over your most recent nights, the heart-rate cycling this screen counts has stayed inside the range of the {n} nights behind it.", "@investigateCvhrInsideUsual": { "description": "Sentence: recent heart-rate cycling has stayed within the user's own usual range", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index de4e02584..4d2118ed2 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1020,7 +1020,6 @@ "investigateDroppedThin": "{count, plural, one{# noche excluida por muy pocas horas observadas} other{# noches excluidas por muy pocas horas observadas}}", "investigateAcrossNOwnNights": "EN {n} DE TUS PROPIAS NOCHES", "investigateCvhrAboveUsual": "En tus noches más recientes, el ciclo de frecuencia cardíaca que mide esta detección ha estado más alto que en las {n} noches que lo respaldan.", - "investigateCvhrNoComparisonYet": "Todavía no hay suficientes noches anteriores para comparar con ellas tu ciclo de frecuencia cardíaca reciente.", "investigateCvhrInsideUsual": "En tus noches más recientes, el ciclo de frecuencia cardíaca que mide esta detección se ha mantenido dentro del rango de las {n} noches que lo respaldan.", "investigateCvhrExplainer": "Es un patrón en tu pulso, no una medición de tu respiración, y no es una prueba de nada. El mismo ciclo se produce por un ritmo irregular, por estar en altitud y por cualquier noche entrecortada — y los betabloqueantes, la diabetes y los trastornos nerviosos lo atenúan, por lo que una respiración realmente alterada muchas veces no deja ninguna huella aquí.", "investigateCvhrNotNegativeResult": "Así que nada de esto es un resultado negativo ni descarta nada, y ninguno de estos datos dice nada sobre una noche en particular — el conteo de una sola noche cambia por docenas de razones por sí solo.", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 478d663ea..d30c7c634 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1020,7 +1020,6 @@ "investigateDroppedThin": "{count, plural, one{# nuit exclue pour trop peu d'heures observées} other{# nuits exclues pour trop peu d'heures observées}}", "investigateAcrossNOwnNights": "SUR {n} DE VOS PROPRES NUITS", "investigateCvhrAboveUsual": "Au cours de vos nuits les plus récentes, le cycle de fréquence cardiaque mesuré par ce dépistage a été plus élevé que sur les {n} nuits qui le composent.", - "investigateCvhrNoComparisonYet": "Il n'y a pas encore assez de nuits antérieures pour y comparer votre cycle de fréquence cardiaque récent.", "investigateCvhrInsideUsual": "Au cours de vos nuits les plus récentes, le cycle de fréquence cardiaque mesuré par ce dépistage est resté dans la plage des {n} nuits qui le composent.", "investigateCvhrExplainer": "C'est un motif dans votre pouls, pas une mesure de votre respiration, et ce n'est un test de rien. Le même cycle provient d'un rythme irrégulier, de l'altitude, ou de toute nuit entrecoupée — et les bêtabloquants, le diabète et les troubles nerveux l'atténuent, si bien qu'une respiration réellement perturbée ne laisse souvent aucune trace ici.", "investigateCvhrNotNegativeResult": "Rien ici n'est donc un résultat négatif et rien ici ne blanchit quoi que ce soit, et rien de tout cela ne dit quoi que ce soit sur une nuit en particulier — le compte d'une seule nuit varie pour une dizaine de raisons à lui seul.", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index cb955d1c6..89f1e08a4 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -1020,7 +1020,6 @@ "investigateDroppedThin": "बहुत कम प्रेक्षित घंटों के कारण {count} रातें बाहर रखी गईं", "investigateAcrossNOwnNights": "आपकी अपनी {n} रातों में", "investigateCvhrAboveUsual": "आपकी हाल की रातों में, इस स्क्रीन द्वारा गिनी गई हृदय-गति साइकलिंग इसके पीछे की {n} रातों के मुक़ाबले अधिक रही है।", - "investigateCvhrNoComparisonYet": "अभी इतनी पुरानी रातें नहीं हैं कि आपकी हाल की हृदय-गति साइकलिंग की उनसे तुलना की जा सके।", "investigateCvhrInsideUsual": "आपकी हाल की रातों में, इस स्क्रीन द्वारा गिनी गई हृदय-गति साइकलिंग इसके पीछे की {n} रातों की सीमा के भीतर बनी रही है।", "investigateCvhrExplainer": "यह आपकी पल्स में एक पैटर्न है, आपकी श्वास का माप नहीं, और यह किसी चीज़ की जाँच नहीं है। यही साइकलिंग अनियमित लय, ऊँचाई पर होने, या किसी भी टूटी हुई रात से आती है — और बीटा-ब्लॉकर्स, डायबिटीज़ और नर्व की स्थितियाँ इसे कम कर देती हैं, इसलिए वास्तव में बिगड़ी हुई श्वास अक्सर यहाँ कोई निशान नहीं छोड़ती।", "investigateCvhrNotNegativeResult": "इसलिए यहाँ कुछ भी नकारात्मक परिणाम नहीं है और यहाँ कुछ भी किसी चीज़ को साफ़ नहीं करता, और इनमें से कोई भी किसी एक रात के बारे में कुछ नहीं कहता — एक अकेली रात की गिनती अपने आप दर्जनों कारणों से बदलती है।", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 424a746a0..9010da858 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -2156,8 +2156,6 @@ } } }, - "investigateCvhrNoComparisonYet": "Пока недостаточно прежних ночей, чтобы сравнить с ними недавние циклические изменения пульса.", - "@investigateCvhrNoComparisonYet": {}, "investigateCvhrInsideUsual": "В последних ночах число циклических изменений пульса, которые учитывает проверка, остаётся в диапазоне предшествующих {n} ночей.", "@investigateCvhrInsideUsual": { "placeholders": { diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 2b510a008..858d2a12d 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1020,7 +1020,6 @@ "investigateDroppedThin": "因观测时长过短而排除 {count} 晚", "investigateAcrossNOwnNights": "基于你自己的 {n} 个夜晚", "investigateCvhrAboveUsual": "在你最近的几个夜晚中,本项筛查所计的心率周期水平高于其背后 {n} 个夜晚的整体水平。", - "investigateCvhrNoComparisonYet": "目前还没有足够多的早前夜晚,可用来与你最近的心率周期水平作比较。", "investigateCvhrInsideUsual": "在你最近的几个夜晚中,本项筛查所计的心率周期水平一直保持在其背后 {n} 个夜晚的范围之内。", "investigateCvhrExplainer": "这是脉搏中的一种模式,不是对呼吸的测量,也不是任何疾病的检测。同样的周期性变化可能来自心律不齐、身处高海拔,或任何断续的夜晚——而 β 受体阻滞剂、糖尿病和神经系统疾病会削弱这种信号,因此真正的呼吸紊乱往往在这里完全不留痕迹。", "investigateCvhrNotNegativeResult": "所以这里的一切都不构成阴性结果,也不能排除任何情况,其中任何一项都不能说明某一个具体夜晚的情况——单单一个夜晚的计数本身就会因十几种原因而波动。", diff --git a/lib/ui2/screens/investigate.dart b/lib/ui2/screens/investigate.dart index 58e96be5d..8af6f8c39 100644 --- a/lib/ui2/screens/investigate.dart +++ b/lib/ui2/screens/investigate.dart @@ -940,13 +940,7 @@ class _InvestigateState extends State { style: F.over.copyWith(color: p.ink3)), const SizedBox(height: S.x3), Text( - // Null until there are enough older nights to compare against; - // reading that as "inside your range" would hide a real jump. - v.aboveOwnUsual == null - ? (l?.investigateCvhrNoComparisonYet ?? - "There aren't enough earlier nights yet to compare your " - 'recent heart-rate cycling against.') - : v.aboveOwnUsual! + v.aboveOwnUsual ? (l?.investigateCvhrAboveUsual(n) ?? 'Over your most recent nights, the heart-rate cycling ' 'this screen counts has been running higher than ' diff --git a/test/ui2_wiring_r2_test.dart b/test/ui2_wiring_r2_test.dart index e054cfd20..cf3f5163e 100644 --- a/test/ui2_wiring_r2_test.dart +++ b/test/ui2_wiring_r2_test.dart @@ -1285,17 +1285,6 @@ void main() { findsOneWidget); }); - testWidgets('too few older nights makes no comparison either way', - (t) async { - final m = ana.cvhrPersonalDistribution(nights(6, recent: 3)); - expect(m.value?.aboveOwnUsual, isNull); - await pumpI(t, m); - expect(find.textContaining("aren't enough earlier nights"), - findsOneWidget); - expect(find.textContaining('running higher'), findsNothing); - expect(find.textContaining('stayed inside'), findsNothing); - }); - testWidgets('too few nights says so instead of showing a partial one', (t) async { await pumpI(t, ana.cvhrPersonalDistribution(nights(3))); From 14c80965f8b0b8e39685ac7d989a0cca44c89ddf Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 19:08:22 +0530 Subject: [PATCH 07/10] Revert "update two fixtures for the new analytics pin" This reverts commit e47262aff4a5b12a609d79ebf2b780f8216e4c7a. --- test/crossday_pipeline_test.dart | 18 ++++++------------ test/sleep_band_trim_wiring_test.dart | 12 ++++-------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/test/crossday_pipeline_test.dart b/test/crossday_pipeline_test.dart index 226d85d33..758e2e978 100644 --- a/test/crossday_pipeline_test.dart +++ b/test/crossday_pipeline_test.dart @@ -192,14 +192,9 @@ void main() { // computed with a hole right at the boundary. test('a hypnogram segment crossing local midnight is not dropped from the ' 'SRI grid', () { - // Local 18:00 → 07:00 the next day, expressed as epoch seconds. Long - // enough that each adjacent-day pair clears the SRI's half-day coverage - // floor; a one-hour night is abstained on whether or not it wraps. - final onset = DateTime(2024, 3, 4, 18).millisecondsSinceEpoch ~/ 1000; - final wake = DateTime(2024, 3, 5, 7).millisecondsSinceEpoch ~/ 1000; - // The same span shifted to sit inside one calendar day: 00:30 → 13:30. - final sameStart = - DateTime(2024, 3, 5, 0, 30).millisecondsSinceEpoch ~/ 1000; + // Local 23:30 → 00:30 the next day, expressed as epoch seconds. + final onset = DateTime(2024, 3, 4, 23, 30).millisecondsSinceEpoch ~/ 1000; + final wake = DateTime(2024, 3, 5, 0, 30).millisecondsSinceEpoch ~/ 1000; List> nights({required bool crossMidnight}) => [ for (var i = 0; i < 14; i++) @@ -207,12 +202,11 @@ void main() { 'date': '2024-03-${(4 + i).toString().padLeft(2, '0')}', 'onset_sec': onset + i * 86400, 'wake_sec': wake + i * 86400, - 'tst_min': 780, + 'tst_min': 60, 'hypnogram': [ { - 'start': (crossMidnight ? onset : sameStart) + i * 86400, - 'end': (crossMidnight ? wake : sameStart + 13 * 3600) + - i * 86400, + 'start': onset + i * 86400, + 'end': (crossMidnight ? wake : onset + 1800) + i * 86400, 'stage': 'nrem', }, ], diff --git a/test/sleep_band_trim_wiring_test.dart b/test/sleep_band_trim_wiring_test.dart index 57fce5304..d6b42a377 100644 --- a/test/sleep_band_trim_wiring_test.dart +++ b/test/sleep_band_trim_wiring_test.dart @@ -268,19 +268,15 @@ void main() { final napStart = _local(2025, 6, 16, 7, 30); - // The lie-in starts 20 minutes after the trimmed wake. The nap detector - // now chains any still block within an hour of the main sleep into the - // night, so it is not a nap candidate even when only the trimmed span is - // excluded. The exclusion below stays as the second line of defence. - test('the detector itself chains the lie-in into the night', () { + test('control: excluding only up to the trimmed wake emits the nap', () { final out = naps(_lieTrimmed); expect(out, isNotNull); expect( - out!.where((n) => + out!.any((n) => (n['start'] as int) >= napStart - 120 && (n['start'] as int) <= napStart + 300), - isEmpty, - reason: 'a still block 20 min after the night is not a nap: $out', + isTrue, + reason: 'the fixture must create a nap candidate: $out', ); }); From 75d19562ff80f68c016e3e6b06c6f1a7499fd75f Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 19:08:22 +0530 Subject: [PATCH 08/10] Revert "repin analytics to main and restamp the freeze snapshots at v117" This reverts commit 39809df7ee5aedd9d02b6e7c2afc969aab8874cf. --- .../fixtures/whoop_freeze/gen4_minus0400.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen4_plus0530.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen4_utc.json | 68 +++++++++---------- .../fixtures/whoop_freeze/gen5_minus0400.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen5_plus0530.json | 68 +++++++++---------- test/fixtures/whoop_freeze/gen5_utc.json | 68 +++++++++---------- 6 files changed, 204 insertions(+), 204 deletions(-) diff --git a/test/fixtures/whoop_freeze/gen4_minus0400.json b/test/fixtures/whoop_freeze/gen4_minus0400.json index 16d93bd94..2509c77ca 100644 --- a/test/fixtures/whoop_freeze/gen4_minus0400.json +++ b/test/fixtures/whoop_freeze/gen4_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "normal", + "band": "suppressed", "saturation_flag": false }, "confidence": 0.9, @@ -24898,11 +24898,11 @@ "readiness": 27.033995461954163, "skipped": 0, "partial": 0, - "payload_sha256": "b57127eaba2e220875324219ed002d3801c330506d1303b87a413572f89ec560" + "payload_sha256": "8c4970c794a3f8bb5664ac877d4bf0657d85be516c6a692b9855bf54afeb92a8" }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25048,11 +25048,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -25061,11 +25061,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -49126,7 +49126,7 @@ "naps": { "value": [ { - "start": 1784050203, + "start": 1784050199, "end": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49158,7 +49158,7 @@ }, { "is_main": false, - "onset_ts": 1784050203, + "onset_ts": 1784050199, "wake_ts": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49591,11 +49591,11 @@ "readiness": 27.03409387728019, "skipped": 0, "partial": 0, - "payload_sha256": "3f4838375946c33e26860d81e49abfb0e7fc17b0087cbac28f3bcb1db8c3b89d" + "payload_sha256": "e61aa65ce319b6077929d91d99aed2e111db9d82efc10a812a017e422838a3dc" }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -49741,11 +49741,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -49754,11 +49754,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -72717,7 +72717,7 @@ "readiness": 66.11544177079463, "skipped": 0, "partial": 0, - "payload_sha256": "eb9d15f24b218b7d4438e5a6504f33efc6a924f513657215fc436bae3d563fb7" + "payload_sha256": "1b08d706da4deab1241c94434834c01d27feb0a4bc00857027c25f42f5808375" } ], "metric_series": [ @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -76923,17 +76923,17 @@ "linked_id": null }, { - "id": "nap:1784050203", + "id": "nap:1784050199", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784050203, + "start_ts": 1784050199, "end_ts": 1784052901, - "detection_start": 1784050203, + "detection_start": 1784050199, "detection_end": 1784052901, - "details_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784050203" + "linked_id": "2026-07-14:1784050199" }, { "id": "2026-07-15:1784151128", @@ -76978,10 +76978,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784050203, + "start_ts": 1784050199, "end_ts": 1784052901, "source": "confirmed", - "payload_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen4_plus0530.json b/test/fixtures/whoop_freeze/gen4_plus0530.json index 928411ce5..4f489c854 100644 --- a/test/fixtures/whoop_freeze/gen4_plus0530.json +++ b/test/fixtures/whoop_freeze/gen4_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "normal", + "band": "suppressed", "saturation_flag": false }, "confidence": 0.9, @@ -24898,11 +24898,11 @@ "readiness": 27.03382323567632, "skipped": 0, "partial": 0, - "payload_sha256": "cda75458f39702ac4580c5d03d4bf6a6b5c5120aee516e8c32d1c6fe33383def" + "payload_sha256": "6af3a3dd03487fb00e59cee8fc3b80d13d8b3df613625f0e53e6b354b3beacae" }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25048,11 +25048,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -25061,11 +25061,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -49126,7 +49126,7 @@ "naps": { "value": [ { - "start": 1784016002, + "start": 1784015998, "end": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49158,7 +49158,7 @@ }, { "is_main": false, - "onset_ts": 1784016002, + "onset_ts": 1784015998, "wake_ts": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49591,11 +49591,11 @@ "readiness": 27.033601802905416, "skipped": 0, "partial": 0, - "payload_sha256": "3228493c5545d3a4ee5f2da9410317da44cf8e9947d17b049572ca698c63112d" + "payload_sha256": "1a10d8277390720929818867fe39e2a3ae139149d0d93057c2ca4f1776cae03b" }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -49741,11 +49741,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -49754,11 +49754,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -72717,7 +72717,7 @@ "readiness": 66.1155535435143, "skipped": 0, "partial": 0, - "payload_sha256": "0187cd292873351886d856d95ba367289227f875a585b0bbbee6c5525617a6da" + "payload_sha256": "180be6438701ff7edef6abd47022db857f820e5821842d48daad59504205106f" } ], "metric_series": [ @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -76923,17 +76923,17 @@ "linked_id": null }, { - "id": "nap:1784016002", + "id": "nap:1784015998", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784016002, + "start_ts": 1784015998, "end_ts": 1784018701, - "detection_start": 1784016002, + "detection_start": 1784015998, "detection_end": 1784018701, - "details_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784016002" + "linked_id": "2026-07-14:1784015998" }, { "id": "2026-07-15:1784116928", @@ -76978,10 +76978,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784016002, + "start_ts": 1784015998, "end_ts": 1784018701, "source": "confirmed", - "payload_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen4_utc.json b/test/fixtures/whoop_freeze/gen4_utc.json index 8627a4f89..080f8e0ad 100644 --- a/test/fixtures/whoop_freeze/gen4_utc.json +++ b/test/fixtures/whoop_freeze/gen4_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "normal", + "band": "suppressed", "saturation_flag": false }, "confidence": 0.9, @@ -24898,11 +24898,11 @@ "readiness": 27.03355259577805, "skipped": 0, "partial": 0, - "payload_sha256": "f13bcc5af9185bb1b8384a9bc439a551a03bc4367ea2fba85c5742ef910df9d8" + "payload_sha256": "3e26efc18e699e2f58ece9a0e85a82907b9f0fab3816fdd3c37d2f94353d3f9b" }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25048,11 +25048,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -25061,11 +25061,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -49126,7 +49126,7 @@ "naps": { "value": [ { - "start": 1784035804, + "start": 1784035800, "end": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49158,7 +49158,7 @@ }, { "is_main": false, - "onset_ts": 1784035804, + "onset_ts": 1784035800, "wake_ts": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49591,11 +49591,11 @@ "readiness": 27.033651010089166, "skipped": 0, "partial": 0, - "payload_sha256": "411649f61ac1083a68de60dd1ff589276d011a075e7d22d81f88d4a692c5346a" + "payload_sha256": "6aa01c2a1822f99c76ac72f5d48c790b012350d756d6d634761d6c3391bbf2a8" }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -49741,11 +49741,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -49754,11 +49754,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -72717,7 +72717,7 @@ "readiness": 66.11559080104756, "skipped": 0, "partial": 0, - "payload_sha256": "26aef4d4f03d8744be1225adb85776a659769af4bd0c02091696b58efd7e48fe" + "payload_sha256": "eb87bade45c3cb62e08cf93cfced5112d7de421c1b54917e24403c9288eb2e12" } ], "metric_series": [ @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -76923,17 +76923,17 @@ "linked_id": null }, { - "id": "nap:1784035804", + "id": "nap:1784035800", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784035804, + "start_ts": 1784035800, "end_ts": 1784038502, - "detection_start": 1784035804, + "detection_start": 1784035800, "detection_end": 1784038502, - "details_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784035804" + "linked_id": "2026-07-14:1784035800" }, { "id": "2026-07-15:1784136728", @@ -76978,10 +76978,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784035804, + "start_ts": 1784035800, "end_ts": 1784038502, "source": "confirmed", - "payload_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen5_minus0400.json b/test/fixtures/whoop_freeze/gen5_minus0400.json index 0c226d0f9..c1752aa1d 100644 --- a/test/fixtures/whoop_freeze/gen5_minus0400.json +++ b/test/fixtures/whoop_freeze/gen5_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "normal", + "band": "suppressed", "saturation_flag": false }, "confidence": 0.9, @@ -25076,11 +25076,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "a3f73d5823f32766fd6f8741f46e2a72ac064ea73b044321b9ebb50480b75058" + "payload_sha256": "d11bcb420276e13e38219499ddd2158c7a0ded41bcd103f4a82b0999296363e1" }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25226,11 +25226,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -25239,11 +25239,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -49477,7 +49477,7 @@ "naps": { "value": [ { - "start": 1784050203, + "start": 1784050199, "end": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49509,7 +49509,7 @@ }, { "is_main": false, - "onset_ts": 1784050203, + "onset_ts": 1784050199, "wake_ts": 1784052901, "duration_min": 45, "in_bed_min": 45, @@ -49942,11 +49942,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "9cc78bf91ecb2c555fe49878acefe1b2eea8f2e8b6746d742c03f8287350fcaa" + "payload_sha256": "1f75b2b3f4d709b60f33261cb89dbddcfb09a714912de305780e481ed9dd91be" }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -50092,11 +50092,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -50105,11 +50105,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -73230,7 +73230,7 @@ "readiness": 61.79377627786914, "skipped": 0, "partial": 0, - "payload_sha256": "e8a33133f77bf08bec2c0293cf63f699c19f63a18ad915ec4228cc244786d195" + "payload_sha256": "3e6d6de8482792a8bc10c95274ccada375153d5d4cff0de81562a61c0ec371f7" } ], "metric_series": [ @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -77436,17 +77436,17 @@ "linked_id": null }, { - "id": "nap:1784050203", + "id": "nap:1784050199", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784050203, + "start_ts": 1784050199, "end_ts": 1784052901, - "detection_start": 1784050203, + "detection_start": 1784050199, "detection_end": 1784052901, - "details_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784050203" + "linked_id": "2026-07-14:1784050199" }, { "id": "2026-07-15:1784151134", @@ -77491,10 +77491,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784050203, + "start_ts": 1784050199, "end_ts": 1784052901, "source": "confirmed", - "payload_json": "{\"start\":1784050203,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784050199,\"end\":1784052901,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen5_plus0530.json b/test/fixtures/whoop_freeze/gen5_plus0530.json index 612a5dd00..05bb93f35 100644 --- a/test/fixtures/whoop_freeze/gen5_plus0530.json +++ b/test/fixtures/whoop_freeze/gen5_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "normal", + "band": "suppressed", "saturation_flag": false }, "confidence": 0.9, @@ -25076,11 +25076,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "a6bb812440c40efd53dc915e78474d6581b354a787fd83f1d8d82274e94b052b" + "payload_sha256": "123df037199b6fbdfe0cb1298838389c45534d672ba2df685d019a3e2b93e047" }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25226,11 +25226,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -25239,11 +25239,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -49477,7 +49477,7 @@ "naps": { "value": [ { - "start": 1784016002, + "start": 1784015998, "end": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49509,7 +49509,7 @@ }, { "is_main": false, - "onset_ts": 1784016002, + "onset_ts": 1784015998, "wake_ts": 1784018701, "duration_min": 45, "in_bed_min": 45, @@ -49942,11 +49942,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "e6ee25535499c542ebd13b8a1df85566c229944efba4dbdb8a44ca980c6442dc" + "payload_sha256": "56e0e7b112441f73b1849430ffdf15fb10beeced9ef19d505ffb9359afb45262" }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -50092,11 +50092,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -50105,11 +50105,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -73230,7 +73230,7 @@ "readiness": 61.79377627786914, "skipped": 0, "partial": 0, - "payload_sha256": "0ba224b91e74c386567f55d2b31b8346e4601bd61161202740d4bd0a7fa97f2c" + "payload_sha256": "3d0fc39b9ecb2646dec22203f8d82e2b3b035486921a383e012bdca3a8a6fb9f" } ], "metric_series": [ @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -77436,17 +77436,17 @@ "linked_id": null }, { - "id": "nap:1784016002", + "id": "nap:1784015998", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784016002, + "start_ts": 1784015998, "end_ts": 1784018701, - "detection_start": 1784016002, + "detection_start": 1784015998, "detection_end": 1784018701, - "details_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784016002" + "linked_id": "2026-07-14:1784015998" }, { "id": "2026-07-15:1784116934", @@ -77491,10 +77491,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784016002, + "start_ts": 1784015998, "end_ts": 1784018701, "source": "confirmed", - "payload_json": "{\"start\":1784016002,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784015998,\"end\":1784018701,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ diff --git a/test/fixtures/whoop_freeze/gen5_utc.json b/test/fixtures/whoop_freeze/gen5_utc.json index 909c35e0f..f09f6882b 100644 --- a/test/fixtures/whoop_freeze/gen5_utc.json +++ b/test/fixtures/whoop_freeze/gen5_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -148,11 +148,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -161,11 +161,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -175,7 +175,7 @@ "cv_pct": 1.688921, "z": -1.056045, "swc": 0.033448, - "band": "normal", + "band": "suppressed", "saturation_flag": false }, "confidence": 0.9, @@ -25076,11 +25076,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "64bd6e2d3cd9fb8a3762d32513c756dbfe5d33e204538d64f6188eb88b25afff" + "payload_sha256": "1dc0892666ef22d6728bd2329f6bda7eacbe551676ce6c1b623df833b5e5bd9b" }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -25226,11 +25226,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -25239,11 +25239,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -49477,7 +49477,7 @@ "naps": { "value": [ { - "start": 1784035804, + "start": 1784035800, "end": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49509,7 +49509,7 @@ }, { "is_main": false, - "onset_ts": 1784035804, + "onset_ts": 1784035800, "wake_ts": 1784038502, "duration_min": 45, "in_bed_min": 45, @@ -49942,11 +49942,11 @@ "readiness": 72.95885235383324, "skipped": 0, "partial": 0, - "payload_sha256": "42d874e0691a2e1f19f3ca870dbf497fd820f6daa556da8bec1cbc7f62b661ca" + "payload_sha256": "e82f76c2d4cd34faf73db2fa0f439fe79a9d1442f0862c3bd711d5b14e436d40" }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -50092,11 +50092,11 @@ "kind": "DC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA DC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA DC; needs a long overnight RR record for mortality-grade stability" }, "prsa_ac": { "value": { @@ -50105,11 +50105,11 @@ "kind": "AC" }, "confidence": 0.95, - "tier": "RELATIVE", + "tier": "HIGH", "inputs_used": [ "rr_cleaned" ], - "note": "Bauer 2006 PRSA AC; relative to own baseline on one device family only" + "note": "Bauer 2006 PRSA AC; needs a long overnight RR record for mortality-grade stability" }, "readiness_lnrmssd": { "value": { @@ -73230,7 +73230,7 @@ "readiness": 61.79377627786914, "skipped": 0, "partial": 0, - "payload_sha256": "a63132ca185866d1519d888273fa38ecc42d26e091cdb18f4a5ba41823294b6c" + "payload_sha256": "99f2bd90847f90067a05a6e034c5e248bbd84a45ee0b7e515ab6074556bb8a44" } ], "metric_series": [ @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 116, "payload_json": { "day_id": "2026-07-15", "active_min": 40, @@ -77436,17 +77436,17 @@ "linked_id": null }, { - "id": "nap:1784035804", + "id": "nap:1784035800", "kind": "nap", "day_id": "2026-07-14", - "start_ts": 1784035804, + "start_ts": 1784035800, "end_ts": 1784038502, - "detection_start": 1784035804, + "detection_start": 1784035800, "detection_end": 1784038502, - "details_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", + "details_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85}", "status": "confirmed", "revision": 0, - "linked_id": "2026-07-14:1784035804" + "linked_id": "2026-07-14:1784035800" }, { "id": "2026-07-15:1784136734", @@ -77491,10 +77491,10 @@ "sleep_nap": [ { "day_id": "2026-07-14", - "start_ts": 1784035804, + "start_ts": 1784035800, "end_ts": 1784038502, "source": "confirmed", - "payload_json": "{\"start\":1784035804,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" + "payload_json": "{\"start\":1784035800,\"end\":1784038502,\"duration_min\":45,\"in_bed_min\":45,\"efficiency\":1.0,\"confidence\":0.85,\"source\":\"confirmed\"}" } ], "crossday_input": [ From d273fc2f56a0a6d2f21dbe8aebcab80fe0730ec7 Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 19:15:06 +0530 Subject: [PATCH 09/10] keep the nap fix on the current analytics pin, at v117 the newer analytics needs its own pass over the low-res device tests, so it doesn't ride in here. this keeps the edge-side nap change only. --- lib/compute/derivation_engine.dart | 14 ++++---------- pubspec.lock | 8 ++++---- pubspec.yaml | 5 +---- test/fixtures/whoop_freeze/gen4_minus0400.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen4_plus0530.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen4_utc.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen5_minus0400.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen5_plus0530.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen5_utc.json | 18 +++++++++--------- 9 files changed, 63 insertions(+), 72 deletions(-) diff --git a/lib/compute/derivation_engine.dart b/lib/compute/derivation_engine.dart index b8541ea2f..8d35b8353 100644 --- a/lib/compute/derivation_engine.dart +++ b/lib/compute/derivation_engine.dart @@ -1825,13 +1825,9 @@ import 'vendor_sleep.dart'; // carries a workout-raised headline; a logged nap over the main sleep is // counted once; an implausible stored age is named as the reason strain, // calories and zones are absent. -// 116 → 117: analytics repinned to main @ 7e4f734 (sleep staging + naps, -// HRV/PRSA tiers): main-sleep selection shares the detector's 90-minute -// continuation limit, so a second sleep block after an hour-long awakening -// stays in the night, with the gap kept as wake/unobserved. A legacy nap -// snapshot fully inside the corrected main window is no longer counted on -// top of it; partial overlaps keep their recorded minutes, and a nap the -// user put back stays theirs. +// 116 → 117 (edge-only): a legacy nap snapshot fully inside the corrected +// main window is no longer counted on top of it; partial overlaps keep their +// recorded minutes, and a nap the user put back stays theirs. const int kAlgoVersion = 117; /// The sibling SHAs this version was derived against, asserted against /// pubspec.yaml in test/db_serve_version_and_reads_test.dart. @@ -2018,9 +2014,7 @@ const int kAlgoVersion = 117; // REPIN @ 77fe373: analytics main, #95 merge (readiness autonomic // merge + spread calibration + capped re-centring + robust lnRMSSD // centre), for v112. -// REPIN @ 7e4f734: analytics main, #100 merge on top of #101 (sleep -// staging + naps, HRV/PRSA tiers), for v117. -const String kAnalyticsPin = '7e4f73467611aad8279b8b276caed07f5f476469'; +const String kAnalyticsPin = '77fe373eb819fda235f80610e898a4bc20a7a249'; // Repinned to analytics main's tip, which carries BOTH PR #72 (hrv_freq // Welch gap guard) and PR #73 (overreachingConjunction rhr quantum guard) — // the two independent kAlgoVersion bumps above (93 and 94). Verified both diff --git a/pubspec.lock b/pubspec.lock index 7f765f95c..3a0609822 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -937,8 +937,8 @@ packages: dependency: "direct main" description: path: "." - ref: 7e4f73467611aad8279b8b276caed07f5f476469 - resolved-ref: 7e4f73467611aad8279b8b276caed07f5f476469 + ref: "77fe373eb819fda235f80610e898a4bc20a7a249" + resolved-ref: "77fe373eb819fda235f80610e898a4bc20a7a249" url: "https://github.com/OpenStrap/analytics.git" source: git version: "1.0.0" @@ -946,8 +946,8 @@ packages: dependency: "direct main" description: path: "." - ref: 89080bcfac7767b3a871fd3a7d9307f5f30dad26 - resolved-ref: 89080bcfac7767b3a871fd3a7d9307f5f30dad26 + ref: "89080bcfac7767b3a871fd3a7d9307f5f30dad26" + resolved-ref: "89080bcfac7767b3a871fd3a7d9307f5f30dad26" url: "https://github.com/OpenStrap/protocol.git" source: git version: "1.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7eb7115f2..3501cd10e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -512,10 +512,7 @@ dependencies: # analytics main @ 77fe373, the #95 merge (tree-identical to its head # 608c46f): readiness autonomic merge + spread calibration + capped # re-centring + robust lnRMSSD centre, for kAlgoVersion 112. - # analytics main @ 7e4f734, the #100 merge (on top of #101): main-sleep - # selection shares the detector's 90-minute continuation limit and the - # 16 h cap, for kAlgoVersion 117. - ref: 7e4f73467611aad8279b8b276caed07f5f476469 + ref: 77fe373eb819fda235f80610e898a4bc20a7a249 # BLE — flutter_blue_plus is the maintained cross-platform GATT client. flutter_blue_plus: ^1.36.8 diff --git a/test/fixtures/whoop_freeze/gen4_minus0400.json b/test/fixtures/whoop_freeze/gen4_minus0400.json index 2509c77ca..887783571 100644 --- a/test/fixtures/whoop_freeze/gen4_minus0400.json +++ b/test/fixtures/whoop_freeze/gen4_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_plus0530.json b/test/fixtures/whoop_freeze/gen4_plus0530.json index 4f489c854..f56647ae3 100644 --- a/test/fixtures/whoop_freeze/gen4_plus0530.json +++ b/test/fixtures/whoop_freeze/gen4_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_utc.json b/test/fixtures/whoop_freeze/gen4_utc.json index 080f8e0ad..685a4c57b 100644 --- a/test/fixtures/whoop_freeze/gen4_utc.json +++ b/test/fixtures/whoop_freeze/gen4_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_minus0400.json b/test/fixtures/whoop_freeze/gen5_minus0400.json index c1752aa1d..9c0ce70c2 100644 --- a/test/fixtures/whoop_freeze/gen5_minus0400.json +++ b/test/fixtures/whoop_freeze/gen5_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_plus0530.json b/test/fixtures/whoop_freeze/gen5_plus0530.json index 05bb93f35..2efc7740d 100644 --- a/test/fixtures/whoop_freeze/gen5_plus0530.json +++ b/test/fixtures/whoop_freeze/gen5_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_utc.json b/test/fixtures/whoop_freeze/gen5_utc.json index f09f6882b..8415368ca 100644 --- a/test/fixtures/whoop_freeze/gen5_utc.json +++ b/test/fixtures/whoop_freeze/gen5_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 116, + "algo_version": 117, "payload_json": { "day_id": "2026-07-15", "active_min": 40, From 81d378bf3ea2fa67afcb92ff860e183fa1c9b613 Mon Sep 17 00:00:00 2001 From: abdulsaheel Date: Sat, 31 Oct 2026 20:01:56 +0530 Subject: [PATCH 10/10] restamp the freeze snapshots at v118 --- test/fixtures/whoop_freeze/gen4_minus0400.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen4_plus0530.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen4_utc.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen5_minus0400.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen5_plus0530.json | 18 +++++++++--------- test/fixtures/whoop_freeze/gen5_utc.json | 18 +++++++++--------- 6 files changed, 54 insertions(+), 54 deletions(-) diff --git a/test/fixtures/whoop_freeze/gen4_minus0400.json b/test/fixtures/whoop_freeze/gen4_minus0400.json index 887783571..97568e47e 100644 --- a/test/fixtures/whoop_freeze/gen4_minus0400.json +++ b/test/fixtures/whoop_freeze/gen4_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_plus0530.json b/test/fixtures/whoop_freeze/gen4_plus0530.json index f56647ae3..90d00fec4 100644 --- a/test/fixtures/whoop_freeze/gen4_plus0530.json +++ b/test/fixtures/whoop_freeze/gen4_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen4_utc.json b/test/fixtures/whoop_freeze/gen4_utc.json index 685a4c57b..5056dbb23 100644 --- a/test/fixtures/whoop_freeze/gen4_utc.json +++ b/test/fixtures/whoop_freeze/gen4_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -24902,7 +24902,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49595,7 +49595,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73355,7 +73355,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73363,7 +73363,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73371,7 +73371,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen4", "coverage_devices": "", @@ -73381,7 +73381,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -74589,7 +74589,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -75797,7 +75797,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_minus0400.json b/test/fixtures/whoop_freeze/gen5_minus0400.json index 9c0ce70c2..e1948c8ae 100644 --- a/test/fixtures/whoop_freeze/gen5_minus0400.json +++ b/test/fixtures/whoop_freeze/gen5_minus0400.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_plus0530.json b/test/fixtures/whoop_freeze/gen5_plus0530.json index 2efc7740d..a1d19b1e3 100644 --- a/test/fixtures/whoop_freeze/gen5_plus0530.json +++ b/test/fixtures/whoop_freeze/gen5_plus0530.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-14", "active_min": 240, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-15", "active_min": 40, diff --git a/test/fixtures/whoop_freeze/gen5_utc.json b/test/fixtures/whoop_freeze/gen5_utc.json index 8415368ca..9656ebbd8 100644 --- a/test/fixtures/whoop_freeze/gen5_utc.json +++ b/test/fixtures/whoop_freeze/gen5_utc.json @@ -2,7 +2,7 @@ "day_result": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-13", "day_confidence": 0.6, @@ -25080,7 +25080,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-14", "day_confidence": 0.6, @@ -49946,7 +49946,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "date": "2026-07-15", "day_confidence": 0.6, @@ -73868,7 +73868,7 @@ "metric_series_version": [ { "date": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73876,7 +73876,7 @@ }, { "date": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73884,7 +73884,7 @@ }, { "date": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "source": "band", "device_family": "gen5", "coverage_devices": "", @@ -73894,7 +73894,7 @@ "wake_day_features": [ { "day_id": "2026-07-13", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-13", "active_min": 90, @@ -75102,7 +75102,7 @@ }, { "day_id": "2026-07-14", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-14", "active_min": 239, @@ -76310,7 +76310,7 @@ }, { "day_id": "2026-07-15", - "algo_version": 117, + "algo_version": 118, "payload_json": { "day_id": "2026-07-15", "active_min": 40,