diff --git a/Packages/StrandAnalytics/Sources/StrandAnalytics/ChargeDrivers.swift b/Packages/StrandAnalytics/Sources/StrandAnalytics/ChargeDrivers.swift index befbf878c6..4c9ee3b5ed 100644 --- a/Packages/StrandAnalytics/Sources/StrandAnalytics/ChargeDrivers.swift +++ b/Packages/StrandAnalytics/Sources/StrandAnalytics/ChargeDrivers.swift @@ -170,70 +170,81 @@ extension RecoveryScorer { // ── HRV (dominant driver; always present once the score exists) ────────── // Higher HRV vs baseline supports recovery. Neutral = HRV at the baseline mean. + let hrvPoints = points(recovery(hrv: hrvBaseline.baseline, rhr: rhr, resp: resp, + hrvBaseline: hrvBaseline, rhrBaseline: rhrB, + respBaseline: respBaseline, sleepPerf: sleepPerf, + skinTempDev: skinTempDev)) drivers.append(ChargeDriver( label: "Heart rate variability", - deltaPoints: points(recovery(hrv: hrvBaseline.baseline, rhr: rhr, resp: resp, - hrvBaseline: hrvBaseline, rhrBaseline: rhrB, - respBaseline: respBaseline, sleepPerf: sleepPerf, - skinTempDev: skinTempDev)), + deltaPoints: hrvPoints, valueText: "\(Int(hrv.rounded())) ms", baselineText: "\(Int(hrvBaseline.baseline.rounded())) ms baseline", verdict: hrvVerdict(value: hrv, baseline: hrvBaseline.baseline, - saturationDetected: hrvSaturationDetected))) + shown: hrv.rounded(), shownBaseline: hrvBaseline.baseline.rounded(), + points: hrvPoints, saturationDetected: hrvSaturationDetected))) // ── Resting HR (lower vs baseline supports recovery) ───────────────────── // Neutral = resting HR at the baseline mean. if let b = rhrB { + let rhrPoints = points(recovery(hrv: hrv, rhr: b.baseline, resp: resp, + hrvBaseline: hrvBaseline, rhrBaseline: rhrB, + respBaseline: respBaseline, sleepPerf: sleepPerf, + skinTempDev: skinTempDev)) drivers.append(ChargeDriver( label: "Resting heart rate", - deltaPoints: points(recovery(hrv: hrv, rhr: b.baseline, resp: resp, - hrvBaseline: hrvBaseline, rhrBaseline: rhrB, - respBaseline: respBaseline, sleepPerf: sleepPerf, - skinTempDev: skinTempDev)), + deltaPoints: rhrPoints, valueText: "\(Int(rhr.rounded())) bpm", baselineText: "\(Int(b.baseline.rounded())) bpm baseline", - verdict: rhrVerdict(value: rhr, baseline: b.baseline))) + verdict: lowerIsBetterVerdict(value: rhr, baseline: b.baseline, + shown: rhr.rounded(), shownBaseline: b.baseline.rounded(), + points: rhrPoints))) } // ── Rest quality (the Rest composite; neutral at sleepPerfCenter) ──────── if let sp = sleepPerf { + let sleepPoints = points(recovery(hrv: hrv, rhr: rhr, resp: resp, + hrvBaseline: hrvBaseline, rhrBaseline: rhrB, + respBaseline: respBaseline, sleepPerf: sleepPerfCenter, + skinTempDev: skinTempDev)) drivers.append(ChargeDriver( label: "Sleep quality", - deltaPoints: points(recovery(hrv: hrv, rhr: rhr, resp: resp, - hrvBaseline: hrvBaseline, rhrBaseline: rhrB, - respBaseline: respBaseline, sleepPerf: sleepPerfCenter, - skinTempDev: skinTempDev)), + deltaPoints: sleepPoints, valueText: "\(Int((sp * 100).rounded()))%", baselineText: "", // centred on a fixed "good night", not a learned baseline - verdict: sleepVerdict(sleepPerf: sp))) + verdict: sleepVerdict(points: sleepPoints))) } // ── Respiration (lower vs baseline supports recovery) ──────────────────── // Neutral = respiration at the baseline mean. if let r = resp, let b = respBaseline { - drivers.append(ChargeDriver( - label: "Respiratory rate", - deltaPoints: points(recovery(hrv: hrv, rhr: rhr, resp: b.baseline, + let respPoints = points(recovery(hrv: hrv, rhr: rhr, resp: b.baseline, hrvBaseline: hrvBaseline, rhrBaseline: rhrB, respBaseline: respBaseline, sleepPerf: sleepPerf, - skinTempDev: skinTempDev)), + skinTempDev: skinTempDev)) + drivers.append(ChargeDriver( + label: "Respiratory rate", + deltaPoints: respPoints, valueText: String(format: "%.1f br/min", locale: Locale(identifier: "en_US_POSIX"), r), baselineText: String(format: "%.1f br/min baseline", locale: Locale(identifier: "en_US_POSIX"), b.baseline), - verdict: respVerdict(value: r, baseline: b.baseline))) + verdict: lowerIsBetterVerdict(value: r, baseline: b.baseline, + shown: (r * 10).rounded() / 10, + shownBaseline: (b.baseline * 10).rounded() / 10, + points: respPoints))) } // ── Skin-temp deviation (symmetric penalty: any drift lowers Charge) ───── // Neutral = zero drift, so the delta is always <= 0 (a penalty removed). if let dev = skinTempDev { - drivers.append(ChargeDriver( - label: "Skin temperature", - deltaPoints: points(recovery(hrv: hrv, rhr: rhr, resp: resp, + let skinPoints = points(recovery(hrv: hrv, rhr: rhr, resp: resp, hrvBaseline: hrvBaseline, rhrBaseline: rhrB, respBaseline: respBaseline, sleepPerf: sleepPerf, - skinTempDev: 0)), + skinTempDev: 0)) + drivers.append(ChargeDriver( + label: "Skin temperature", + deltaPoints: skinPoints, valueText: skinTempDevText(dev), baselineText: "", // a deviation already; the reference is the personal baseline (0) - verdict: skinTempVerdict(dev))) + verdict: skinTempVerdict(dev, points: skinPoints))) } // Biggest mover first; stable on ties (preserves the append order above). @@ -251,42 +262,68 @@ extension RecoveryScorer { // When adding or rewording a verdict, add the identical key to Strand's Localizable.xcstrings; // Tools/test_home_i18n.py enforces that complete engine-to-catalog contract. - static func hrvVerdict(value: Double, baseline: Double, saturationDetected: Bool = false) -> String { - if value > baseline { return "above baseline, supporting recovery" } - if value < baseline { - // Parasympathetic-saturation signature detected: resting HR is also low and decoupled from - // HRV. NAME the pattern, but keep the plain "limiting recovery" read, because that is what - // the score actually did: the easing is detected-only and did NOT change these points. The - // hedge is deliberate too, since the same low-HRV + low-RHR pattern is also reported for - // non-functional overreaching, which is the opposite of benign. - return saturationDetected - ? "below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue" - : "below baseline, limiting recovery" - } - return "at baseline" + // A verdict must agree with the two things its row shows: the value against its baseline at the + // precision printed, and the rounded points. The EFFECT (supporting / limiting) comes from the points; + // the DIRECTION from the printed values, falling back to the raw ones only when the printed values tie + // and the term still moved the score, which is then said as "slightly". Comparing raw values alone let + // a row read "51 bpm · 51 bpm baseline · 0 pts" and still say "above baseline, limiting recovery". + + /// Where a value sits for the verdict: nil when the row honestly reads as at baseline. Kotlin twin: + /// `RecoveryDrivers.direction`. + private static func direction(value: Double, baseline: Double, shown: Double, shownBaseline: Double, + points: Int) -> (higher: Bool, slight: Bool)? { + if shown != shownBaseline { return (shown > shownBaseline, false) } + if points == 0 || value == baseline { return nil } + return (value > baseline, true) } - static func rhrVerdict(value: Double, baseline: Double) -> String { - if value < baseline { return "below baseline, supporting recovery" } - if value > baseline { return "above baseline, limiting recovery" } - return "at baseline" + /// HRV's verdict. Kotlin twin: `RecoveryDrivers.hrvVerdict`. + static func hrvVerdict(value: Double, baseline: Double, shown: Double, shownBaseline: Double, + points: Int, saturationDetected: Bool = false) -> String { + guard let d = direction(value: value, baseline: baseline, shown: shown, shownBaseline: shownBaseline, + points: points) else { return "at baseline" } + if points == 0 { + return d.higher ? "above baseline, too small to change Charge" : "below baseline, too small to change Charge" + } + if d.higher { return d.slight ? "slightly above baseline, supporting recovery" : "above baseline, supporting recovery" } + // Parasympathetic-saturation signature detected: resting HR is also low and decoupled from + // HRV. NAME the pattern, but keep the plain "limiting recovery" read, because that is what + // the score actually did: the easing is detected-only and did NOT change these points. The + // hedge is deliberate too, since the same low-HRV + low-RHR pattern is also reported for + // non-functional overreaching, which is the opposite of benign. + if saturationDetected { + return "below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue" + } + return d.slight ? "slightly below baseline, limiting recovery" : "below baseline, limiting recovery" } - static func respVerdict(value: Double, baseline: Double) -> String { - if value < baseline { return "below baseline, supporting recovery" } - if value > baseline { return "above baseline, limiting recovery" } - return "at baseline" + /// Resting HR and respiration, where lower than baseline supports recovery. `shown` and + /// `shownBaseline` are the values at the precision the row prints them. Kotlin twin: + /// `RecoveryDrivers.lowerIsBetterVerdict`. + static func lowerIsBetterVerdict(value: Double, baseline: Double, shown: Double, shownBaseline: Double, + points: Int) -> String { + guard let d = direction(value: value, baseline: baseline, shown: shown, shownBaseline: shownBaseline, + points: points) else { return "at baseline" } + if points == 0 { + return d.higher ? "above baseline, too small to change Charge" : "below baseline, too small to change Charge" + } + if d.higher { return d.slight ? "slightly above baseline, limiting recovery" : "above baseline, limiting recovery" } + return d.slight ? "slightly below baseline, supporting recovery" : "below baseline, supporting recovery" } - static func sleepVerdict(sleepPerf: Double) -> String { - if sleepPerf > sleepPerfCenter { return "a strong night, supporting recovery" } - if sleepPerf < sleepPerfCenter { return "below a good night, limiting recovery" } + /// Rest quality's verdict, from its points. Kotlin twin: `RecoveryDrivers.sleepVerdict`. + static func sleepVerdict(points: Int) -> String { + if points > 0 { return "a strong night, supporting recovery" } + if points < 0 { return "below a good night, limiting recovery" } return "a typical night" } - static func skinTempVerdict(_ dev: Double) -> String { - // Symmetric penalty: any drift from baseline lowers Charge; at baseline it is neutral. - if abs(dev) <= skinTempTypicalBandC { return "near baseline" } + /// Skin temperature's verdict: near baseline exactly when the drift cost 0 points. Kotlin twin: + /// `RecoveryDrivers.skinTempVerdict`. + static func skinTempVerdict(_ dev: Double, points: Int) -> String { + // Symmetric penalty: any drift lowers Charge, so points are never positive. Near baseline means + // the drift cost nothing at the shown precision; otherwise the sign of the drift names it. + if points == 0 { return "near baseline" } return dev > 0 ? "warmer than baseline, limiting recovery" : "cooler than baseline, limiting recovery" diff --git a/Packages/StrandAnalytics/Tests/StrandAnalyticsTests/ChargeDriversTests.swift b/Packages/StrandAnalytics/Tests/StrandAnalyticsTests/ChargeDriversTests.swift index 04555893c6..1aeb07327b 100644 --- a/Packages/StrandAnalytics/Tests/StrandAnalyticsTests/ChargeDriversTests.swift +++ b/Packages/StrandAnalytics/Tests/StrandAnalyticsTests/ChargeDriversTests.swift @@ -103,7 +103,7 @@ final class ChargeDriversTests: XCTestCase { deltaPoints: -1, valueText: "30 ms", baselineText: "30 ms baseline", - verdict: "below baseline, limiting recovery")]) + verdict: "slightly below baseline, limiting recovery")]) } // MARK: - Presence / omission @@ -169,7 +169,32 @@ final class ChargeDriversTests: XCTestCase { XCTAssertGreaterThanOrEqual(resp.deltaPoints, 0) // minor 0.05-weight term; direction below XCTAssertTrue(hrv.verdict.contains("supporting recovery")) XCTAssertTrue(rhr.verdict.contains("supporting recovery")) - XCTAssertTrue(resp.verdict.contains("supporting recovery")) + // A minor term that rounds to 0 points states its direction without claiming an effect. + XCTAssertTrue(resp.deltaPoints > 0 ? resp.verdict == "below baseline, supporting recovery" + : resp.verdict == "below baseline, too small to change Charge") + } + + /// The row's words must agree with what the row prints: equal printed values read "at baseline" even + /// when the raw values differ, a difference worth 0 points claims no effect, and skin temperature is + /// "near baseline" only when it cost nothing. + func testVerdictsAgreeWithThePrintedValuesAndPoints() { + typealias R = RecoveryScorer + // Printed 51 vs 51, worth 0 points: at baseline, whatever the raw values. + XCTAssertEqual(R.lowerIsBetterVerdict(value: 51.3, baseline: 50.8, shown: 51, shownBaseline: 51, points: 0), + "at baseline") + // Printed tie that still cost a point: said as slight, never as "at baseline". + XCTAssertEqual(R.lowerIsBetterVerdict(value: 51.3, baseline: 50.8, shown: 51, shownBaseline: 51, points: -1), + "slightly above baseline, limiting recovery") + // A printed difference worth 0 points claims no effect. + XCTAssertEqual(R.lowerIsBetterVerdict(value: 52, baseline: 51, shown: 52, shownBaseline: 51, points: 0), + "above baseline, too small to change Charge") + XCTAssertEqual(R.lowerIsBetterVerdict(value: 55, baseline: 51, shown: 55, shownBaseline: 51, points: -3), + "above baseline, limiting recovery") + XCTAssertEqual(R.hrvVerdict(value: 40, baseline: 50, shown: 40, shownBaseline: 50, points: -8), + "below baseline, limiting recovery") + XCTAssertEqual(R.hrvVerdict(value: 50, baseline: 50, shown: 50, shownBaseline: 50, points: 0), "at baseline") + XCTAssertEqual(R.skinTempVerdict(0.2, points: -1), "warmer than baseline, limiting recovery") + XCTAssertEqual(R.skinTempVerdict(0.2, points: 0), "near baseline") } func testBadInputsGiveNegativeContributions() { diff --git a/Strand/Resources/Localizable.xcstrings b/Strand/Resources/Localizable.xcstrings index 5490e95478..c5293f8881 100644 --- a/Strand/Resources/Localizable.xcstrings +++ b/Strand/Resources/Localizable.xcstrings @@ -1,6 +1,24 @@ { "sourceLanguage": "en", "strings": { + "above baseline, too small to change Charge": { "localizations": { + "de": {"stringUnit": {"state": "translated", "value": "über der Basislinie, zu gering, um die Energie zu ändern"}}, "es": {"stringUnit": {"state": "translated", "value": "por encima de tu línea base, demasiado poco para cambiar la Carga"}}, "fr": {"stringUnit": {"state": "translated", "value": "au-dessus de la référence, trop peu pour changer la Charge"}}, "it": {"stringUnit": {"state": "translated", "value": "sopra la linea di base, troppo poco per cambiare la Carica"}}, "pl": {"stringUnit": {"state": "translated", "value": "powyżej wartości wyjściowej, za mało, by zmienić Energię"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "acima da linha de base, pouco demais para alterar a Carga"}}, "ru": {"stringUnit": {"state": "translated", "value": "выше нормы, слишком мало, чтобы изменить Заряд"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "高于基线,幅度太小,不影响能量"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "高於基線,幅度太小,不影響能量"}} + } }, + "below baseline, too small to change Charge": { "localizations": { + "de": {"stringUnit": {"state": "translated", "value": "unter der Basislinie, zu gering, um die Energie zu ändern"}}, "es": {"stringUnit": {"state": "translated", "value": "por debajo de tu línea base, demasiado poco para cambiar la Carga"}}, "fr": {"stringUnit": {"state": "translated", "value": "en dessous de la référence, trop peu pour changer la Charge"}}, "it": {"stringUnit": {"state": "translated", "value": "sotto la linea di base, troppo poco per cambiare la Carica"}}, "pl": {"stringUnit": {"state": "translated", "value": "poniżej wartości wyjściowej, za mało, by zmienić Energię"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "abaixo da linha de base, pouco demais para alterar a Carga"}}, "ru": {"stringUnit": {"state": "translated", "value": "ниже нормы, слишком мало, чтобы изменить Заряд"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "低于基线,幅度太小,不影响能量"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "低於基線,幅度太小,不影響能量"}} + } }, + "slightly above baseline, supporting recovery": { "localizations": { + "de": {"stringUnit": {"state": "translated", "value": "leicht über der Basislinie, stützt die Erholung"}}, "es": {"stringUnit": {"state": "translated", "value": "ligeramente por encima de tu línea base, favorece la recuperación"}}, "fr": {"stringUnit": {"state": "translated", "value": "légèrement au-dessus de la référence, favorise la récupération"}}, "it": {"stringUnit": {"state": "translated", "value": "leggermente sopra la linea di base, favorisce il recupero"}}, "pl": {"stringUnit": {"state": "translated", "value": "nieco powyżej wartości wyjściowej, wspierając powrót do zdrowia"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "ligeiramente acima da linha de base, apoiando a recuperação"}}, "ru": {"stringUnit": {"state": "translated", "value": "немного выше нормы, поддерживает восстановление"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "略高于基线,有助于恢复"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "略高於基線,有助於恢復"}} + } }, + "slightly above baseline, limiting recovery": { "localizations": { + "de": {"stringUnit": {"state": "translated", "value": "leicht über der Basislinie, bremst die Erholung"}}, "es": {"stringUnit": {"state": "translated", "value": "ligeramente por encima de tu línea base, limita la recuperación"}}, "fr": {"stringUnit": {"state": "translated", "value": "légèrement au-dessus de la référence, limite la récupération"}}, "it": {"stringUnit": {"state": "translated", "value": "leggermente sopra la linea di base, limita il recupero"}}, "pl": {"stringUnit": {"state": "translated", "value": "nieco powyżej wartości wyjściowej, ograniczając powrót do zdrowia"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "ligeiramente acima da linha de base, limitando a recuperação"}}, "ru": {"stringUnit": {"state": "translated", "value": "немного выше нормы, ограничивает восстановление"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "略高于基线,限制恢复"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "略高於基線,限制恢復"}} + } }, + "slightly below baseline, supporting recovery": { "localizations": { + "de": {"stringUnit": {"state": "translated", "value": "leicht unter der Basislinie, stützt die Erholung"}}, "es": {"stringUnit": {"state": "translated", "value": "ligeramente por debajo de tu línea base, favorece la recuperación"}}, "fr": {"stringUnit": {"state": "translated", "value": "légèrement en dessous de la référence, favorise la récupération"}}, "it": {"stringUnit": {"state": "translated", "value": "leggermente sotto la linea di base, favorisce il recupero"}}, "pl": {"stringUnit": {"state": "translated", "value": "nieco poniżej wartości wyjściowej, wspierając powrót do zdrowia"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "ligeiramente abaixo da linha de base, apoiando a recuperação"}}, "ru": {"stringUnit": {"state": "translated", "value": "немного ниже нормы, поддерживает восстановление"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "略低于基线,有助于恢复"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "略低於基線,有助於恢復"}} + } }, + "slightly below baseline, limiting recovery": { "localizations": { + "de": {"stringUnit": {"state": "translated", "value": "leicht unter der Basislinie, bremst die Erholung"}}, "es": {"stringUnit": {"state": "translated", "value": "ligeramente por debajo de tu línea base, limita la recuperación"}}, "fr": {"stringUnit": {"state": "translated", "value": "légèrement en dessous de la référence, limite la récupération"}}, "it": {"stringUnit": {"state": "translated", "value": "leggermente sotto la linea di base, limita il recupero"}}, "pl": {"stringUnit": {"state": "translated", "value": "nieco poniżej wartości wyjściowej, ograniczając powrót do zdrowia"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "ligeiramente abaixo da linha de base, limitando a recuperação"}}, "ru": {"stringUnit": {"state": "translated", "value": "немного ниже нормы, ограничивает восстановление"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "略低于基线,限制恢复"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "略低於基線,限制恢復"}} + } }, "Ring battery %lld percent": { "localizations": { "de": {"stringUnit": {"state": "translated", "value": "Ring-Akku %lld Prozent"}}, "es": {"stringUnit": {"state": "translated", "value": "Batería del anillo %lld por ciento"}}, "fr": {"stringUnit": {"state": "translated", "value": "Batterie de la bague %lld pour cent"}}, "it": {"stringUnit": {"state": "translated", "value": "Batteria dell'anello %lld percento"}}, "pl": {"stringUnit": {"state": "translated", "value": "Bateria pierścienia %lld procent"}}, "pt-PT": {"stringUnit": {"state": "translated", "value": "Bateria do anel %lld por cento"}}, "ru": {"stringUnit": {"state": "translated", "value": "Заряд кольца %lld процентов"}}, "zh-Hans": {"stringUnit": {"state": "translated", "value": "戒指电量百分之 %lld"}}, "zh-Hant": {"stringUnit": {"state": "translated", "value": "戒指電量百分之 %lld"}} } }, diff --git a/Tools/test_home_i18n.py b/Tools/test_home_i18n.py index c9570d4e87..b99ac298b1 100644 --- a/Tools/test_home_i18n.py +++ b/Tools/test_home_i18n.py @@ -422,9 +422,11 @@ def test_apple_charge_driver_verdicts_are_complete_catalog_keys(self) -> None: "static func skinTempDevText", 1 )[0] verdicts = set(re.findall(r'(?:return|\?|:)\s*"([^"]+)"', verdict_block)) - # Thirteen return paths currently collapse to twelve unique keys because several helpers share - # "at baseline". Pin the unique-key set size so syntax changes cannot silently evade extraction. - self.assertEqual(12, len(verdicts), "Verdict extraction changed; review the catalog contract") + # Eighteen unique keys: the twelve original verdicts, plus the "slightly" (printed values tie but + # the term still moved the score) and "too small to change Charge" (a printed difference worth 0 + # points) wordings for the baseline-relative terms. Pin the unique-key set size so syntax changes + # cannot silently evade extraction. + self.assertEqual(18, len(verdicts), "Verdict extraction changed; review the catalog contract") catalog = audit.load_catalog(ROOT / "Strand/Resources/Localizable.xcstrings") missing = [] diff --git a/android/app/src/main/java/com/noop/analytics/RecoveryDrivers.kt b/android/app/src/main/java/com/noop/analytics/RecoveryDrivers.kt index b91876dc48..452750cec5 100644 --- a/android/app/src/main/java/com/noop/analytics/RecoveryDrivers.kt +++ b/android/app/src/main/java/com/noop/analytics/RecoveryDrivers.kt @@ -1,6 +1,7 @@ package com.noop.analytics import kotlin.math.abs +import kotlin.math.floor // RecoveryDrivers.kt - the USER-FACING "What shaped it" breakdown for the Charge (recovery) score. // @@ -63,6 +64,12 @@ enum class ChargeDriverVerdict { NEAR_BASELINE, WARMER_THAN_BASELINE_LIMITING, COOLER_THAN_BASELINE_LIMITING, + SLIGHTLY_ABOVE_BASELINE_SUPPORTING, + SLIGHTLY_BELOW_BASELINE_SUPPORTING, + SLIGHTLY_ABOVE_BASELINE_LIMITING, + SLIGHTLY_BELOW_BASELINE_LIMITING, + ABOVE_BASELINE_TOO_SMALL, + BELOW_BASELINE_TOO_SMALL, } data class ChargeDriver( @@ -135,6 +142,10 @@ object RecoveryDrivers { return if (delta < 0.0) -Math.round(-delta).toInt() else Math.round(delta).toInt() } + // Swift `Double.rounded()` (nearest, half away from zero): the precision each row prints its value + // and baseline at, which the verdicts compare, so the words and the printed numbers agree. + val roundHalfAway: (Double) -> Double = { x -> if (x >= 0.0) floor(x + 0.5) else -floor(-x + 0.5) } + // Did the parasympathetic-saturation signature fire on THIS night (low HRV corroborated by a low, // decoupled resting HR)? Detection ONLY: the guard's easing is not applied, so deltaPoints below is // the full, unguarded HRV penalty. The verdict merely NAMES the detected pattern so the UI can @@ -150,101 +161,118 @@ object RecoveryDrivers { val drivers = ArrayList() // HRV (dominant driver; always present once the score exists). Neutral = HRV at the baseline mean. + val hrvPoints = points( + RecoveryScorer.recovery( + hrv = hrvBaseline.baseline, rhr = rhr, resp = resp, + hrvBaseline = hrvBaseline, rhrBaseline = rhrB, + respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = skinTempDev, + ), + ) drivers.add( ChargeDriver( label = ChargeDriverLabel.HEART_RATE_VARIABILITY, - deltaPoints = points( - RecoveryScorer.recovery( - hrv = hrvBaseline.baseline, rhr = rhr, resp = resp, - hrvBaseline = hrvBaseline, rhrBaseline = rhrB, - respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = skinTempDev, - ), - ), + deltaPoints = hrvPoints, value = hrv, baseline = hrvBaseline.baseline, unit = ChargeDriverUnit.MILLISECONDS, verdict = hrvVerdict( value = hrv, baseline = hrvBaseline.baseline, + shown = roundHalfAway(hrv), + shownBaseline = roundHalfAway(hrvBaseline.baseline), + points = hrvPoints, saturationDetected = hrvSaturationDetected, ), ), ) // Resting HR (lower vs baseline supports recovery). Neutral = resting HR at the baseline mean. if (rhrB != null) { + val rhrPoints = points( + RecoveryScorer.recovery( + hrv = hrv, rhr = rhrB.baseline, resp = resp, + hrvBaseline = hrvBaseline, rhrBaseline = rhrB, + respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = skinTempDev, + ), + ) drivers.add( ChargeDriver( label = ChargeDriverLabel.RESTING_HEART_RATE, - deltaPoints = points( - RecoveryScorer.recovery( - hrv = hrv, rhr = rhrB.baseline, resp = resp, - hrvBaseline = hrvBaseline, rhrBaseline = rhrB, - respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = skinTempDev, - ), - ), + deltaPoints = rhrPoints, value = rhr, baseline = rhrB.baseline, unit = ChargeDriverUnit.BEATS_PER_MINUTE, - verdict = rhrVerdict(value = rhr, baseline = rhrB.baseline), + verdict = lowerIsBetterVerdict( + value = rhr, baseline = rhrB.baseline, + shown = roundHalfAway(rhr), shownBaseline = roundHalfAway(rhrB.baseline), + points = rhrPoints, + ), ), ) } // Rest quality (the Rest composite; neutral at sleepPerfCenter). if (sleepPerf != null) { + val sleepPoints = points( + RecoveryScorer.recovery( + hrv = hrv, rhr = rhr, resp = resp, + hrvBaseline = hrvBaseline, rhrBaseline = rhrB, + respBaseline = respBaseline, sleepPerf = RecoveryScorer.sleepPerfCenter, + skinTempDev = skinTempDev, + ), + ) drivers.add( ChargeDriver( label = ChargeDriverLabel.SLEEP_QUALITY, - deltaPoints = points( - RecoveryScorer.recovery( - hrv = hrv, rhr = rhr, resp = resp, - hrvBaseline = hrvBaseline, rhrBaseline = rhrB, - respBaseline = respBaseline, sleepPerf = RecoveryScorer.sleepPerfCenter, - skinTempDev = skinTempDev, - ), - ), + deltaPoints = sleepPoints, value = sleepPerf * 100.0, baseline = null, unit = ChargeDriverUnit.PERCENT, - verdict = sleepVerdict(sleepPerf), + verdict = sleepVerdict(sleepPoints), ), ) } // Respiration (lower vs baseline supports recovery). Neutral = respiration at the baseline mean. if (resp != null && respBaseline != null) { + val respPoints = points( + RecoveryScorer.recovery( + hrv = hrv, rhr = rhr, resp = respBaseline.baseline, + hrvBaseline = hrvBaseline, rhrBaseline = rhrB, + respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = skinTempDev, + ), + ) drivers.add( ChargeDriver( label = ChargeDriverLabel.RESPIRATORY_RATE, - deltaPoints = points( - RecoveryScorer.recovery( - hrv = hrv, rhr = rhr, resp = respBaseline.baseline, - hrvBaseline = hrvBaseline, rhrBaseline = rhrB, - respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = skinTempDev, - ), - ), + deltaPoints = respPoints, value = resp, baseline = respBaseline.baseline, unit = ChargeDriverUnit.BREATHS_PER_MINUTE, - verdict = respVerdict(value = resp, baseline = respBaseline.baseline), + verdict = lowerIsBetterVerdict( + value = resp, baseline = respBaseline.baseline, + shown = roundHalfAway(resp * 10.0) / 10.0, + shownBaseline = roundHalfAway(respBaseline.baseline * 10.0) / 10.0, + points = respPoints, + ), ), ) } // Skin-temp deviation (symmetric penalty: any drift lowers Charge). Neutral = zero drift, so the // delta is always <= 0 (a penalty removed). Surface it as a RELATIVE deviation, never an absolute. if (skinTempDev != null) { + val skinPoints = points( + RecoveryScorer.recovery( + hrv = hrv, rhr = rhr, resp = resp, + hrvBaseline = hrvBaseline, rhrBaseline = rhrB, + respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = 0.0, + ), + ) drivers.add( ChargeDriver( label = ChargeDriverLabel.SKIN_TEMPERATURE, - deltaPoints = points( - RecoveryScorer.recovery( - hrv = hrv, rhr = rhr, resp = resp, - hrvBaseline = hrvBaseline, rhrBaseline = rhrB, - respBaseline = respBaseline, sleepPerf = sleepPerf, skinTempDev = 0.0, - ), - ), + deltaPoints = skinPoints, value = skinTempDev, baseline = null, unit = ChargeDriverUnit.CELSIUS_DEVIATION, - verdict = skinTempVerdict(skinTempDev), + verdict = skinTempVerdict(skinTempDev, skinPoints), ), ) } @@ -254,47 +282,80 @@ object RecoveryDrivers { } /** - * HRV verdict matching the Swift canonical `hrvVerdict(value:baseline:saturationDetected:)`: above - * baseline supports recovery; below baseline limits it; at baseline is neutral. When the - * parasympathetic-saturation signature fired (low HRV corroborated by a low, decoupled resting HR) the - * pattern is NAMED, but the "limiting recovery" read stays, because that is what the score actually did: - * the easing is detected-only and did NOT change these points. The hedge is deliberate too, since the - * same low-HRV + low-RHR pattern is also reported for non-functional overreaching, which is the opposite - * of benign. Byte-for-byte the same strings as the iOS twin. + * A verdict must agree with the two things its row shows: the value against its baseline at the + * precision printed, and the rounded points. The EFFECT (supporting / limiting) comes from the points; + * the DIRECTION from the printed values, falling back to the raw ones only when the printed values tie + * and the term still moved the score ("slightly"). Twin of the Swift `RecoveryScorer.direction`. + * + * @return null when the row honestly reads as at baseline, else (higher, slight). */ - private fun hrvVerdict( + private fun direction( value: Double, baseline: Double, - saturationDetected: Boolean, - ): ChargeDriverVerdict = when { - value > baseline -> ChargeDriverVerdict.ABOVE_BASELINE_SUPPORTING - value < baseline -> - if (saturationDetected) { - ChargeDriverVerdict.HRV_SATURATION_LIMITING - } else { - ChargeDriverVerdict.BELOW_BASELINE_LIMITING - } - else -> ChargeDriverVerdict.AT_BASELINE + shown: Double, + shownBaseline: Double, + points: Int, + ): Pair? { + if (shown != shownBaseline) return (shown > shownBaseline) to false + if (points == 0 || value == baseline) return null + return (value > baseline) to true } - /** Resting-HR verdict (lower is better). Mirrors Swift `rhrVerdict` exactly. */ - private fun rhrVerdict(value: Double, baseline: Double): ChargeDriverVerdict = when { - value < baseline -> ChargeDriverVerdict.BELOW_BASELINE_SUPPORTING - value > baseline -> ChargeDriverVerdict.ABOVE_BASELINE_LIMITING - else -> ChargeDriverVerdict.AT_BASELINE + /** + * HRV verdict. Twin of the Swift `RecoveryScorer.hrvVerdict`. + * When the parasympathetic-saturation signature fired (low HRV corroborated by a low, decoupled resting + * HR) the pattern is NAMED, but the "limiting recovery" read stays, because that is what the score + * actually did: the easing is detected-only and did NOT change these points. The hedge is deliberate + * too, since the same low-HRV + low-RHR pattern is also reported for non-functional overreaching, + * which is the opposite of benign. + */ + private fun hrvVerdict( + value: Double, + baseline: Double, + shown: Double, + shownBaseline: Double, + points: Int, + saturationDetected: Boolean, + ): ChargeDriverVerdict { + val (higher, slight) = direction(value, baseline, shown, shownBaseline, points) + ?: return ChargeDriverVerdict.AT_BASELINE + if (points == 0) { + return if (higher) ChargeDriverVerdict.ABOVE_BASELINE_TOO_SMALL else ChargeDriverVerdict.BELOW_BASELINE_TOO_SMALL + } + if (higher) { + return if (slight) ChargeDriverVerdict.SLIGHTLY_ABOVE_BASELINE_SUPPORTING + else ChargeDriverVerdict.ABOVE_BASELINE_SUPPORTING + } + if (saturationDetected) return ChargeDriverVerdict.HRV_SATURATION_LIMITING + return if (slight) ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_LIMITING + else ChargeDriverVerdict.BELOW_BASELINE_LIMITING } - /** Respiration verdict (lower is better). Mirrors Swift `respVerdict` exactly. */ - private fun respVerdict(value: Double, baseline: Double): ChargeDriverVerdict = when { - value < baseline -> ChargeDriverVerdict.BELOW_BASELINE_SUPPORTING - value > baseline -> ChargeDriverVerdict.ABOVE_BASELINE_LIMITING - else -> ChargeDriverVerdict.AT_BASELINE + /** Resting HR and respiration (lower is better). Twin of the Swift `RecoveryScorer.lowerIsBetterVerdict`. */ + private fun lowerIsBetterVerdict( + value: Double, + baseline: Double, + shown: Double, + shownBaseline: Double, + points: Int, + ): ChargeDriverVerdict { + val (higher, slight) = direction(value, baseline, shown, shownBaseline, points) + ?: return ChargeDriverVerdict.AT_BASELINE + if (points == 0) { + return if (higher) ChargeDriverVerdict.ABOVE_BASELINE_TOO_SMALL else ChargeDriverVerdict.BELOW_BASELINE_TOO_SMALL + } + return when { + higher && slight -> ChargeDriverVerdict.SLIGHTLY_ABOVE_BASELINE_LIMITING + higher -> ChargeDriverVerdict.ABOVE_BASELINE_LIMITING + slight -> ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_SUPPORTING + else -> ChargeDriverVerdict.BELOW_BASELINE_SUPPORTING + } } - /** Rest-quality verdict (higher is better), centred on sleepPerfCenter. Mirrors Swift `sleepVerdict`. */ - private fun sleepVerdict(sleepPerf: Double): ChargeDriverVerdict = when { - sleepPerf > RecoveryScorer.sleepPerfCenter -> ChargeDriverVerdict.STRONG_NIGHT_SUPPORTING - sleepPerf < RecoveryScorer.sleepPerfCenter -> ChargeDriverVerdict.BELOW_GOOD_NIGHT_LIMITING + /** Rest-quality verdict from its points. Twin of the Swift `RecoveryScorer.sleepVerdict`. */ + private fun sleepVerdict(points: Int): ChargeDriverVerdict = when { + points > 0 -> ChargeDriverVerdict.STRONG_NIGHT_SUPPORTING + points < 0 -> ChargeDriverVerdict.BELOW_GOOD_NIGHT_LIMITING else -> ChargeDriverVerdict.TYPICAL_NIGHT } @@ -302,11 +363,11 @@ object RecoveryDrivers { private const val SKIN_TEMP_TYPICAL_BAND_C: Double = 0.3 /** - * Skin-temp verdict (symmetric): a drift within the typical band reads neutral, beyond it limits - * recovery, warmer or cooler. Mirrors the Swift skinTempVerdict exactly. + * Skin-temp verdict: any drift lowers Charge, so it is "near baseline" exactly when it cost 0 points; + * otherwise the sign of the drift names it. Twin of the Swift `RecoveryScorer.skinTempVerdict`. */ - private fun skinTempVerdict(dev: Double): ChargeDriverVerdict = when { - abs(dev) <= SKIN_TEMP_TYPICAL_BAND_C -> ChargeDriverVerdict.NEAR_BASELINE + private fun skinTempVerdict(dev: Double, points: Int): ChargeDriverVerdict = when { + points == 0 -> ChargeDriverVerdict.NEAR_BASELINE dev > 0.0 -> ChargeDriverVerdict.WARMER_THAN_BASELINE_LIMITING else -> ChargeDriverVerdict.COOLER_THAN_BASELINE_LIMITING } diff --git a/android/app/src/main/java/com/noop/ui/TodayScreen.kt b/android/app/src/main/java/com/noop/ui/TodayScreen.kt index d63c8b590e..8eff491152 100644 --- a/android/app/src/main/java/com/noop/ui/TodayScreen.kt +++ b/android/app/src/main/java/com/noop/ui/TodayScreen.kt @@ -5558,6 +5558,12 @@ private fun DriverRow(driver: ChargeDriver) { ChargeDriverVerdict.NEAR_BASELINE -> uiString(R.string.today_driver_near_baseline) ChargeDriverVerdict.WARMER_THAN_BASELINE_LIMITING -> uiString(R.string.today_driver_warmer_limiting) ChargeDriverVerdict.COOLER_THAN_BASELINE_LIMITING -> uiString(R.string.today_driver_cooler_limiting) + ChargeDriverVerdict.SLIGHTLY_ABOVE_BASELINE_SUPPORTING -> uiString(R.string.today_driver_slightly_above_supporting) + ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_SUPPORTING -> uiString(R.string.today_driver_slightly_below_supporting) + ChargeDriverVerdict.SLIGHTLY_ABOVE_BASELINE_LIMITING -> uiString(R.string.today_driver_slightly_above_limiting) + ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_LIMITING -> uiString(R.string.today_driver_slightly_below_limiting) + ChargeDriverVerdict.ABOVE_BASELINE_TOO_SMALL -> uiString(R.string.today_driver_above_too_small) + ChargeDriverVerdict.BELOW_BASELINE_TOO_SMALL -> uiString(R.string.today_driver_below_too_small) } val driverA11y = uiString(R.string.today_driver_a11y, label, valueText, baselineText, signed, verdict) Row( diff --git a/android/app/src/main/res/values-de/strings.xml b/android/app/src/main/res/values-de/strings.xml index e32258e341..6138b6451f 100644 --- a/android/app/src/main/res/values-de/strings.xml +++ b/android/app/src/main/res/values-de/strings.xml @@ -2474,6 +2474,12 @@ nahe am Basiswert wärmer als der Basiswert, begrenzt die Erholung kühler als der Basiswert, begrenzt die Erholung + leicht über dem Basiswert, unterstützt die Erholung + leicht unter dem Basiswert, unterstützt die Erholung + leicht über dem Basiswert, begrenzt die Erholung + leicht unter dem Basiswert, begrenzt die Erholung + über dem Basiswert, zu gering, um die Energie zu ändern + unter dem Basiswert, zu gering, um die Energie zu ändern %1$s, %2$s, %3$s, %4$s Punkte, %5$s Deine Tageswerte Die drei Werte diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml index 80d7754c46..a8bb1623d0 100644 --- a/android/app/src/main/res/values-es/strings.xml +++ b/android/app/src/main/res/values-es/strings.xml @@ -2461,6 +2461,12 @@ cerca de la referencia más alta que la referencia, limita la recuperación más baja que la referencia, limita la recuperación + ligeramente por encima de la referencia, favorece la recuperación + ligeramente por debajo de la referencia, favorece la recuperación + ligeramente por encima de la referencia, limita la recuperación + ligeramente por debajo de la referencia, limita la recuperación + por encima de la referencia, demasiado poco para cambiar la Carga + por debajo de la referencia, demasiado poco para cambiar la Carga %1$s, %2$s, %3$s, %4$s puntos, %5$s Tus puntuaciones diarias Las tres puntuaciones diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml index 5c6296d88d..6850630557 100644 --- a/android/app/src/main/res/values-fr/strings.xml +++ b/android/app/src/main/res/values-fr/strings.xml @@ -2460,6 +2460,12 @@ proche de la référence plus chaude que la référence, limite la récupération plus froide que la référence, limite la récupération + légèrement au-dessus de la référence, favorise la récupération + légèrement sous la référence, favorise la récupération + légèrement au-dessus de la référence, limite la récupération + légèrement sous la référence, limite la récupération + au-dessus de la référence, trop peu pour changer l\'Énergie + sous la référence, trop peu pour changer l\'Énergie %1$s, %2$s, %3$s, %4$s points, %5$s Vos scores quotidiens Les trois scores diff --git a/android/app/src/main/res/values-it/strings.xml b/android/app/src/main/res/values-it/strings.xml index b118569b08..80641709d4 100644 --- a/android/app/src/main/res/values-it/strings.xml +++ b/android/app/src/main/res/values-it/strings.xml @@ -2526,6 +2526,12 @@ vicino alla linea di base più calda della linea di base, limita il recupero più fredda della linea di base, limita il recupero + leggermente sopra la linea di base, favorisce il recupero + leggermente sotto la linea di base, favorisce il recupero + leggermente sopra la linea di base, limita il recupero + leggermente sotto la linea di base, limita il recupero + sopra la linea di base, troppo poco per cambiare la Carica + sotto la linea di base, troppo poco per cambiare la Carica %1$s, %2$s, %3$s, %4$s punti, %5$s I tuoi punteggi giornalieri I tre punteggi diff --git a/android/app/src/main/res/values-pl/strings.xml b/android/app/src/main/res/values-pl/strings.xml index cca5f132c9..1bc3a30619 100644 --- a/android/app/src/main/res/values-pl/strings.xml +++ b/android/app/src/main/res/values-pl/strings.xml @@ -2469,6 +2469,12 @@ blisko bazy cieplej niż baza, ogranicza regenerację chłodniej niż baza, ogranicza regenerację + nieco powyżej bazy, wspiera regenerację + nieco poniżej bazy, wspiera regenerację + nieco powyżej bazy, ogranicza regenerację + nieco poniżej bazy, ogranicza regenerację + powyżej bazy, za mało, by zmienić Energię + poniżej bazy, za mało, by zmienić Energię %1$s, %2$s, %3$s, %4$s pkt, %5$s Twoje dzienne wyniki Trzy wyniki diff --git a/android/app/src/main/res/values-pt-rPT/strings.xml b/android/app/src/main/res/values-pt-rPT/strings.xml index 0265d6c6e7..3da887effa 100644 --- a/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/android/app/src/main/res/values-pt-rPT/strings.xml @@ -2453,6 +2453,12 @@ perto da referência mais quente do que a referência, limita a recuperação mais fria do que a referência, limita a recuperação + ligeiramente acima da referência, favorece a recuperação + ligeiramente abaixo da referência, favorece a recuperação + ligeiramente acima da referência, limita a recuperação + ligeiramente abaixo da referência, limita a recuperação + acima da referência, pouco demais para alterar a Energia + abaixo da referência, pouco demais para alterar a Energia %1$s, %2$s, %3$s, %4$s pontos, %5$s As tuas pontuações diárias As três pontuações diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml index 8ce4ad3124..c146d91c04 100644 --- a/android/app/src/main/res/values-ru/strings.xml +++ b/android/app/src/main/res/values-ru/strings.xml @@ -2386,6 +2386,12 @@ около нормы теплее нормы, что ограничивает восстановление холоднее нормы, ограничивает восстановление + немного выше нормы, поддерживает восстановление + немного ниже нормы, поддерживает восстановление + немного выше нормы, ограничивает восстановление + немного ниже нормы, ограничивает восстановление + выше нормы, слишком мало, чтобы изменить Заряд + ниже нормы, слишком мало, чтобы изменить Заряд %1$s, %2$s, %3$s, %4$s пунктов, %5$s ВАШИ ЕЖЕДНЕВНЫЕ ПОКАЗАТЕЛИ ТРИ ПОКАЗАТЕЛЯ diff --git a/android/app/src/main/res/values-zh/strings.xml b/android/app/src/main/res/values-zh/strings.xml index 52c536a6a8..330e904801 100644 --- a/android/app/src/main/res/values-zh/strings.xml +++ b/android/app/src/main/res/values-zh/strings.xml @@ -2376,6 +2376,12 @@ 接近基线 高于基线温度,限制恢复 低于基线温度,限制恢复 + 略高于基线,有利于恢复 + 略低于基线,有利于恢复 + 略高于基线,限制恢复 + 略低于基线,限制恢复 + 高于基线,幅度太小,不影响能量 + 低于基线,幅度太小,不影响能量 %1$s,%2$s,%3$s,%4$s 分,%5$s 你的每日评分 三项评分 diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 7f2ac64608..75eb050f4d 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -2582,6 +2582,12 @@ near baseline warmer than baseline, limiting recovery cooler than baseline, limiting recovery + slightly above baseline, supporting recovery + slightly below baseline, supporting recovery + slightly above baseline, limiting recovery + slightly below baseline, limiting recovery + above baseline, too small to change Charge + below baseline, too small to change Charge %1$s, %2$s, %3$s, %4$s points, %5$s Your daily scores The three scores diff --git a/android/app/src/test/java/com/noop/analytics/ChargeDriverVerdictOracleTest.kt b/android/app/src/test/java/com/noop/analytics/ChargeDriverVerdictOracleTest.kt new file mode 100644 index 0000000000..efd16991b8 --- /dev/null +++ b/android/app/src/test/java/com/noop/analytics/ChargeDriverVerdictOracleTest.kt @@ -0,0 +1,365 @@ +package com.noop.analytics + +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Swift-oracle parity for the Charge driver verdicts (ChargeDrivers.swift <-> RecoveryDrivers.kt). + * + * EXPECTED is the verbatim stdout of the Swift `RecoveryScorer.chargeDrivers` run over the same grid + * (HRV, resting HR and respiration either side of their baselines and on the display-rounding edges, + * skin-temperature drift inside and outside the old fixed band, two sleep qualities). Each row is + * `label/points/verdict`, sorted, with the verdict as the Swift catalog string. A verdict must agree with + * the row's printed values and points on both platforms, so the Kotlin twin must reproduce every line. + */ +class ChargeDriverVerdictOracleTest { + + private fun baseline(mean: Double, sigma: Double): BaselineState = + BaselineState( + baseline = mean, spread = sigma / 1.253, nValid = 14, nightsSinceUpdate = 0, + status = BaselineStatus.TRUSTED, + ) + + private val labelText = mapOf( + ChargeDriverLabel.HEART_RATE_VARIABILITY to "Heart rate variability", + ChargeDriverLabel.RESTING_HEART_RATE to "Resting heart rate", + ChargeDriverLabel.SLEEP_QUALITY to "Sleep quality", + ChargeDriverLabel.RESPIRATORY_RATE to "Respiratory rate", + ChargeDriverLabel.SKIN_TEMPERATURE to "Skin temperature", + ) + + /** The Swift verdict string for each Kotlin verdict: the engine-to-catalog contract both share. */ + private val verdictText = mapOf( + ChargeDriverVerdict.ABOVE_BASELINE_SUPPORTING to "above baseline, supporting recovery", + ChargeDriverVerdict.BELOW_BASELINE_SUPPORTING to "below baseline, supporting recovery", + ChargeDriverVerdict.ABOVE_BASELINE_LIMITING to "above baseline, limiting recovery", + ChargeDriverVerdict.BELOW_BASELINE_LIMITING to "below baseline, limiting recovery", + ChargeDriverVerdict.AT_BASELINE to "at baseline", + ChargeDriverVerdict.HRV_SATURATION_LIMITING to + "below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue", + ChargeDriverVerdict.STRONG_NIGHT_SUPPORTING to "a strong night, supporting recovery", + ChargeDriverVerdict.BELOW_GOOD_NIGHT_LIMITING to "below a good night, limiting recovery", + ChargeDriverVerdict.TYPICAL_NIGHT to "a typical night", + ChargeDriverVerdict.NEAR_BASELINE to "near baseline", + ChargeDriverVerdict.WARMER_THAN_BASELINE_LIMITING to "warmer than baseline, limiting recovery", + ChargeDriverVerdict.COOLER_THAN_BASELINE_LIMITING to "cooler than baseline, limiting recovery", + ChargeDriverVerdict.SLIGHTLY_ABOVE_BASELINE_SUPPORTING to "slightly above baseline, supporting recovery", + ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_SUPPORTING to "slightly below baseline, supporting recovery", + ChargeDriverVerdict.SLIGHTLY_ABOVE_BASELINE_LIMITING to "slightly above baseline, limiting recovery", + ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_LIMITING to "slightly below baseline, limiting recovery", + ChargeDriverVerdict.ABOVE_BASELINE_TOO_SMALL to "above baseline, too small to change Charge", + ChargeDriverVerdict.BELOW_BASELINE_TOO_SMALL to "below baseline, too small to change Charge", + ) + + @Test fun everyVerdictHasItsSwiftString() { + assertEquals(ChargeDriverVerdict.entries.toSet(), verdictText.keys) + } + + @Test fun verdictsMatchTheSwiftOracle() { + for (line in EXPECTED.trim().lines()) { + val (inputs, expected) = line.split("|", limit = 2) + val (hrv, rhr, resp, skin, sp) = inputs.split(",").map { it.toDouble() } + val rows = RecoveryDrivers.chargeDrivers( + hrv = hrv, rhr = rhr, resp = resp, + hrvBaseline = baseline(30.0, 6.0), rhrBaseline = baseline(58.0, 3.0), + respBaseline = baseline(16.0, 2.0), sleepPerf = sp, skinTempDev = skin, + ).map { "${labelText.getValue(it.label)}/${it.deltaPoints}/${verdictText.getValue(it.verdict)}" } + .sorted() + .joinToString(";") + assertEquals("inputs $inputs", expected, rows) + } + } + + private companion object { + val EXPECTED = """ +29.6,57.7,15.97,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,15.97,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,15.97,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,15.97,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,15.97,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,15.97,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,16.04,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,16.04,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,16.04,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,16.04,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,16.04,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,16.04,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,17.5,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,17.5,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,17.5,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,17.5,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,57.7,17.5,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,57.7,17.5,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,15.97,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,15.97,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,15.97,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,15.97,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,15.97,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,15.97,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,16.04,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,16.04,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,16.04,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,16.04,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,16.04,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,16.04,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,17.5,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,17.5,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,17.5,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,17.5,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,58.3,17.5,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,58.3,17.5,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,15.97,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,15.97,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,15.97,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,15.97,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,15.97,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,15.97,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,16.04,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,16.04,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,16.04,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,16.04,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,16.04,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,16.04,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,17.5,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,17.5,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,17.5,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,17.5,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,61.0,17.5,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,61.0,17.5,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,15.97,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,15.97,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,15.97,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,15.97,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,15.97,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,15.97,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,16.04,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,16.04,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,16.04,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,16.04,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,16.04,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,16.04,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,17.5,0.1,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,17.5,0.1,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,17.5,0.25,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,17.5,0.25,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +29.6,55.0,17.5,-0.5,0.6|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +29.6,55.0,17.5,-0.5,0.9|Heart rate variability/-1/slightly below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,15.97,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,15.97,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,15.97,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,15.97,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,15.97,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,15.97,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,16.04,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,16.04,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,16.04,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,16.04,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,16.04,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,16.04,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,17.5,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,17.5,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,17.5,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,17.5,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,57.7,17.5,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,57.7,17.5,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,15.97,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,15.97,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,15.97,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,15.97,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,15.97,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,15.97,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,16.04,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,16.04,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,16.04,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,16.04,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,16.04,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,16.04,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,17.5,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,17.5,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,17.5,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,17.5,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,58.3,17.5,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,58.3,17.5,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,15.97,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,15.97,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,15.97,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,15.97,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,15.97,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,15.97,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,16.04,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,16.04,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,16.04,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,16.04,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,16.04,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,16.04,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,17.5,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,17.5,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,17.5,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,17.5,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,61.0,17.5,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,61.0,17.5,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,15.97,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,15.97,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,15.97,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,15.97,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,15.97,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,15.97,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,16.04,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,16.04,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,16.04,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,16.04,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,16.04,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,16.04,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,17.5,0.1,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,17.5,0.1,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,17.5,0.25,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,17.5,0.25,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +30.3,55.0,17.5,-0.5,0.6|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +30.3,55.0,17.5,-0.5,0.9|Heart rate variability/1/slightly above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,15.97,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,15.97,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,15.97,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,15.97,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,15.97,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,15.97,-0.5,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,16.04,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,16.04,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,16.04,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,16.04,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,16.04,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,16.04,-0.5,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,17.5,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,17.5,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,17.5,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,17.5,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,57.7,17.5,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,57.7,17.5,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,15.97,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,15.97,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,15.97,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,15.97,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,15.97,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,15.97,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,16.04,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,16.04,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,16.04,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,16.04,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,16.04,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,16.04,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,17.5,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,17.5,0.1,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,17.5,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,17.5,0.25,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,58.3,17.5,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,58.3,17.5,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,15.97,0.1,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,15.97,0.1,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,15.97,0.25,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,15.97,0.25,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,15.97,-0.5,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,15.97,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,16.04,0.1,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,16.04,0.1,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,16.04,0.25,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,16.04,0.25,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,16.04,-0.5,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,16.04,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,17.5,0.1,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,17.5,0.1,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,17.5,0.25,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,17.5,0.25,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,61.0,17.5,-0.5,0.6|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,61.0,17.5,-0.5,0.9|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-8/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,15.97,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,15.97,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,15.97,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,15.97,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,15.97,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,15.97,-0.5,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,16.04,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,16.04,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,16.04,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,16.04,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,16.04,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,16.04,-0.5,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,17.5,0.1,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,17.5,0.1,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,17.5,0.25,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,17.5,0.25,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +31.0,55.0,17.5,-0.5,0.6|Heart rate variability/4/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +31.0,55.0,17.5,-0.5,0.9|Heart rate variability/3/above baseline, supporting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,15.97,0.1,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-11/below a good night, limiting recovery +24.0,57.7,15.97,0.1,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,15.97,0.25,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-11/below a good night, limiting recovery +24.0,57.7,15.97,0.25,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,15.97,-0.5,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-11/below a good night, limiting recovery +24.0,57.7,15.97,-0.5,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,16.04,0.1,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-11/below a good night, limiting recovery +24.0,57.7,16.04,0.1,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,16.04,0.25,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-11/below a good night, limiting recovery +24.0,57.7,16.04,0.25,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,16.04,-0.5,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-11/below a good night, limiting recovery +24.0,57.7,16.04,-0.5,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,17.5,0.1,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,57.7,17.5,0.1,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,17.5,0.25,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,57.7,17.5,0.25,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,57.7,17.5,-0.5,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-10/below a good night, limiting recovery +24.0,57.7,17.5,-0.5,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/1/slightly below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,15.97,0.1,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,15.97,0.1,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,15.97,0.25,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,15.97,0.25,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,15.97,-0.5,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,15.97,-0.5,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,16.04,0.1,0.6|Heart rate variability/-20/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,16.04,0.1,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,16.04,0.25,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,16.04,0.25,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,16.04,-0.5,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,16.04,-0.5,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,17.5,0.1,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,17.5,0.1,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,17.5,0.25,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,17.5,0.25,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,58.3,17.5,-0.5,0.6|Heart rate variability/-19/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-10/below a good night, limiting recovery +24.0,58.3,17.5,-0.5,0.9|Heart rate variability/-22/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-1/slightly above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,15.97,0.1,0.6|Heart rate variability/-18/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-6/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,15.97,0.1,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,15.97,0.25,0.6|Heart rate variability/-18/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-6/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,15.97,0.25,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,15.97,-0.5,0.6|Heart rate variability/-17/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-6/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,15.97,-0.5,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,16.04,0.1,0.6|Heart rate variability/-18/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-6/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,16.04,0.1,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,16.04,0.25,0.6|Heart rate variability/-17/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-6/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,16.04,0.25,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,16.04,-0.5,0.6|Heart rate variability/-17/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-6/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,16.04,-0.5,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/0/at baseline;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,17.5,0.1,0.6|Heart rate variability/-17/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-5/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,17.5,0.1,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,17.5,0.25,0.6|Heart rate variability/-17/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-5/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,17.5,0.25,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,61.0,17.5,-0.5,0.6|Heart rate variability/-17/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-5/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-9/below a good night, limiting recovery +24.0,61.0,17.5,-0.5,0.9|Heart rate variability/-21/below baseline, limiting recovery;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/-7/above baseline, limiting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,15.97,0.1,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,15.97,0.1,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,15.97,0.25,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,15.97,0.25,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,15.97,-0.5,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/6/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,15.97,-0.5,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,16.04,0.1,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,16.04,0.1,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,16.04,0.25,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/7/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,16.04,0.25,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,16.04,-0.5,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/6/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,16.04,-0.5,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/0/at baseline;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,17.5,0.1,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/6/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-12/below a good night, limiting recovery +24.0,55.0,17.5,0.1,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,17.5,0.25,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/6/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/-11/below a good night, limiting recovery +24.0,55.0,17.5,0.25,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/0/near baseline;Sleep quality/2/a strong night, supporting recovery +24.0,55.0,17.5,-0.5,0.6|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/6/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/-11/below a good night, limiting recovery +24.0,55.0,17.5,-0.5,0.9|Heart rate variability/-21/below baseline, limiting recovery, though low resting HR suggests this may be parasympathetic saturation rather than fatigue;Respiratory rate/-1/above baseline, limiting recovery;Resting heart rate/8/below baseline, supporting recovery;Skin temperature/-1/cooler than baseline, limiting recovery;Sleep quality/2/a strong night, supporting recovery +""" + } +} diff --git a/android/app/src/test/java/com/noop/analytics/RecoveryDriversTest.kt b/android/app/src/test/java/com/noop/analytics/RecoveryDriversTest.kt index 058a113b1d..fe986bf3bd 100644 --- a/android/app/src/test/java/com/noop/analytics/RecoveryDriversTest.kt +++ b/android/app/src/test/java/com/noop/analytics/RecoveryDriversTest.kt @@ -124,7 +124,7 @@ class RecoveryDriversTest { value = 29.99117725828923, baseline = 30.0, unit = ChargeDriverUnit.MILLISECONDS, - verdict = ChargeDriverVerdict.BELOW_BASELINE_LIMITING, + verdict = ChargeDriverVerdict.SLIGHTLY_BELOW_BASELINE_LIMITING, ), ), drivers,