Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ internal fun vo2MaxAttributionSource(estimator: Vo2MaxEstimator?): String =
*/
internal fun vitalChartYDomain(key: String): ClosedFloatingPointRange<Double>? =
when (key) {
"recovery", "sleep_performance", "strain" -> 0.0..100.0
// "rest", NOT "sleep_performance": that is the SERIES name this detail reads underneath, and it is
// never a detail key on Android. Writing the series name here compiled, passed a test asserting it,
// and left the Rest chart auto-scaling exactly as before.
"recovery", "rest", "strain" -> 0.0..100.0
else -> null
}

Expand Down
23 changes: 22 additions & 1 deletion android/app/src/test/java/com/noop/ui/VitalChartShapeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class VitalChartShapeTest {
@Test
fun `percentage metrics anchor to their natural range`() {
assertEquals(0.0..100.0, vitalChartYDomain("recovery"))
assertEquals(0.0..100.0, vitalChartYDomain("sleep_performance"))
assertEquals(0.0..100.0, vitalChartYDomain("rest"))
assertEquals(0.0..100.0, vitalChartYDomain("strain"))
}

Expand All @@ -34,6 +34,27 @@ class VitalChartShapeTest {
assertEquals(0.0..100.0, vitalChartYDomain("strain"))
}

/**
* Every key in the allow-list has to be one the screen ACTUALLY receives. The first version anchored
* "sleep_performance", which is the series this detail reads underneath and never a detail key here,
* so Rest kept auto-scaling while a test asserting that key passed. Pinning against the real key list
* is what makes the allow-list checkable rather than plausible.
*
* `realKeys` is a HAND-MAINTAINED mirror of the `when` in `buildVitalDetail`/`buildSeriesVitalDetail`;
* a unit test cannot enumerate a `when`. It catches an anchored key that no screen sends, which is the
* bug that shipped. It does NOT catch a newly added metric, so a new key belongs here too.
*/
@Test
fun `every anchored key is a real detail key`() {
val realKeys = setOf(
"recovery", "strain", "resp", "spo2", "rhr", "hrv", "skin", "rest",
"fitness_age", "vitality", "vo2max_est", "steps_est",
)
val anchored = realKeys.filter { vitalChartYDomain(it) != null }
assertEquals(setOf("recovery", "rest", "strain"), anchored.toSet())
assertNull(vitalChartYDomain("sleep_performance")) // the series name, not a detail key
}

/**
* Blood oxygen is the case that proves this is not "percentages get 0..100": its real movement lives
* in 90..100, so anchoring would flatten the signal into a line at the top. Metrics with no fixed
Expand Down