mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(measurements): wire W5d Withings enum values into list-meta + chart-tokens
The 7 W5d additions (fat-free mass, fat mass, muscle mass, skin temperature, pulse-wave velocity, vascular age, visceral fat) landed in measurementTypeEnum but the per-type lookup maps and AI-chart allowlist were never extended. Six drift-guard tests caught the gap. Adds icons (Dumbbell for muscle; family-consistent reuse for the rest), chart-bucket colors (mass → chart-1, fat/temp → chart-4, cardio → chart-3, pulse-derived → chart-5), AI chart-token allowlist entries, and orphan-enum strip list entries so raw enum identifiers can never leak through prose. Doctor-report PDF holds the 7 new types under the same v1.5 gate as the v1.4.23 Apple Health metrics until clinical layout + reference ranges are agreed. Baseline: 2537 → 2543 passing tests; typecheck clean.
This commit is contained in:
1 parent
d72c60c098
commit
ca3c225a07
3 files changed
+74
-1
No files matched your search
@@ -29,6 +29,7 @@ import {
|
||||
TrendingUp,
|
||||
Thermometer,
|
||||
Gauge,
|
||||
Dumbbell,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
@@ -52,6 +53,14 @@ export const MEASUREMENT_TYPE_LABEL_KEYS: Record<string, string> = {
|
||||
WALKING_RUNNING_DISTANCE: "measurements.typeWalkingRunningDistance",
|
||||
VO2_MAX: "measurements.typeVo2Max",
|
||||
BODY_TEMPERATURE: "measurements.typeBodyTemperature",
|
||||
// ── v1.4.25 W5d Withings full coverage ──
|
||||
FAT_FREE_MASS: "measurements.typeFatFreeMass",
|
||||
FAT_MASS: "measurements.typeFatMass",
|
||||
MUSCLE_MASS: "measurements.typeMuscleMass",
|
||||
SKIN_TEMPERATURE: "measurements.typeSkinTemperature",
|
||||
PULSE_WAVE_VELOCITY: "measurements.typePulseWaveVelocity",
|
||||
VASCULAR_AGE: "measurements.typeVascularAge",
|
||||
VISCERAL_FAT: "measurements.typeVisceralFat",
|
||||
};
|
||||
|
||||
export const MEASUREMENT_TYPE_ICONS: Record<string, LucideIcon> = {
|
||||
@@ -74,6 +83,19 @@ export const MEASUREMENT_TYPE_ICONS: Record<string, LucideIcon> = {
|
||||
WALKING_RUNNING_DISTANCE: Footprints,
|
||||
VO2_MAX: Gauge,
|
||||
BODY_TEMPERATURE: Thermometer,
|
||||
// ── v1.4.25 W5d Withings full coverage ──
|
||||
// Body-composition trio: Scale carries the mass-family (FFM is the
|
||||
// weight residual after fat); Droplets carries the fat-family
|
||||
// (BODY_FAT already uses it, so FAT_MASS + VISCERAL_FAT match);
|
||||
// Dumbbell is reserved for muscle so the three rows stay distinct
|
||||
// in the list view.
|
||||
FAT_FREE_MASS: Scale,
|
||||
FAT_MASS: Droplets,
|
||||
MUSCLE_MASS: Dumbbell,
|
||||
SKIN_TEMPERATURE: Thermometer,
|
||||
PULSE_WAVE_VELOCITY: Activity,
|
||||
VASCULAR_AGE: HeartPulse,
|
||||
VISCERAL_FAT: Droplets,
|
||||
};
|
||||
|
||||
export const MEASUREMENT_TYPE_COLORS: Record<string, string> = {
|
||||
@@ -96,4 +118,14 @@ export const MEASUREMENT_TYPE_COLORS: Record<string, string> = {
|
||||
WALKING_RUNNING_DISTANCE: "bg-chart-2/20 text-chart-2",
|
||||
VO2_MAX: "bg-chart-1/20 text-chart-1",
|
||||
BODY_TEMPERATURE: "bg-chart-4/20 text-chart-4",
|
||||
// ── v1.4.25 W5d Withings full coverage ──
|
||||
// chart-1 (mass), chart-3 (cardio), chart-4 (fat/temp), chart-5
|
||||
// (pulse-derived) — extend the existing color-family conventions.
|
||||
FAT_FREE_MASS: "bg-chart-1/20 text-chart-1",
|
||||
FAT_MASS: "bg-chart-4/20 text-chart-4",
|
||||
MUSCLE_MASS: "bg-chart-1/20 text-chart-1",
|
||||
SKIN_TEMPERATURE: "bg-chart-4/20 text-chart-4",
|
||||
PULSE_WAVE_VELOCITY: "bg-chart-5/20 text-chart-5",
|
||||
VASCULAR_AGE: "bg-chart-3/20 text-chart-3",
|
||||
VISCERAL_FAT: "bg-chart-4/20 text-chart-4",
|
||||
};
|
||||
@@ -34,10 +34,18 @@ const EXPECTED_TYPES = [
|
||||
"WALKING_RUNNING_DISTANCE",
|
||||
"VO2_MAX",
|
||||
"BODY_TEMPERATURE",
|
||||
// ── v1.4.25 W5d Withings full coverage ──
|
||||
"FAT_FREE_MASS",
|
||||
"FAT_MASS",
|
||||
"MUSCLE_MASS",
|
||||
"SKIN_TEMPERATURE",
|
||||
"PULSE_WAVE_VELOCITY",
|
||||
"VASCULAR_AGE",
|
||||
"VISCERAL_FAT",
|
||||
] as const;
|
||||
|
||||
describe("measurementTypeEnum coverage", () => {
|
||||
it("exposes the 18 canonical measurement types", () => {
|
||||
it("exposes the 25 canonical measurement types", () => {
|
||||
expect([...measurementTypeEnum.options].sort()).toEqual(
|
||||
[...EXPECTED_TYPES].sort(),
|
||||
);
|
||||
@@ -52,6 +60,11 @@ describe("measurementTypeEnum coverage", () => {
|
||||
// the v1.4.23 release of the doctor PDF — they ship into the
|
||||
// clinical surface alongside the iOS app's first paying-customer
|
||||
// sync in v1.5 once layout + reference ranges are agreed.
|
||||
// - v1.4.25 Withings additions (fat-free / fat / muscle mass, skin
|
||||
// temperature, pulse-wave velocity, vascular age, visceral fat) are
|
||||
// held under the same v1.5 gate. Body composition + cardiovascular
|
||||
// risk markers warrant their own clinical layout (reference ranges
|
||||
// differ by sex/age) which lands with the iOS-app clinical surface.
|
||||
// Updates to this set MUST be paired with a comment in
|
||||
// doctor-report-pdf-core.ts so the rationale stays discoverable.
|
||||
const PDF_VITAL_EXCLUSIONS = new Set([
|
||||
@@ -65,6 +78,13 @@ describe("measurementTypeEnum coverage", () => {
|
||||
"WALKING_RUNNING_DISTANCE",
|
||||
"VO2_MAX",
|
||||
"BODY_TEMPERATURE",
|
||||
"FAT_FREE_MASS",
|
||||
"FAT_MASS",
|
||||
"MUSCLE_MASS",
|
||||
"SKIN_TEMPERATURE",
|
||||
"PULSE_WAVE_VELOCITY",
|
||||
"VASCULAR_AGE",
|
||||
"VISCERAL_FAT",
|
||||
]);
|
||||
|
||||
it("doctor-report PDF vital types cover the canonical enum minus documented exclusions", () => {
|
||||
|
||||
@@ -43,6 +43,17 @@ export const ALLOWED_CHART_TOKENS = [
|
||||
"metric:WALKING_RUNNING_DISTANCE",
|
||||
"metric:VO2_MAX",
|
||||
"metric:BODY_TEMPERATURE",
|
||||
// v1.4.25 W5d — Withings full coverage. Same posture as v1.4.23 — the
|
||||
// LLM can reference these in prose; dedicated chart components land in
|
||||
// v1.5 when the Insights body-composition + cardiovascular sub-pages
|
||||
// are designed.
|
||||
"metric:FAT_FREE_MASS",
|
||||
"metric:FAT_MASS",
|
||||
"metric:MUSCLE_MASS",
|
||||
"metric:SKIN_TEMPERATURE",
|
||||
"metric:PULSE_WAVE_VELOCITY",
|
||||
"metric:VASCULAR_AGE",
|
||||
"metric:VISCERAL_FAT",
|
||||
] as const;
|
||||
|
||||
export type ChartToken = (typeof ALLOWED_CHART_TOKENS)[number];
|
||||
@@ -105,6 +116,16 @@ const ORPHAN_ENUMS = [
|
||||
"VO2_MAX",
|
||||
"BODY_TEMPERATURE",
|
||||
"SLEEP_DURATION",
|
||||
// v1.4.25 W5d Withings additions. Multi-word upper-snake enum names
|
||||
// never appear in legitimate user-facing prose, so stripping them
|
||||
// unconditionally is safe.
|
||||
"FAT_FREE_MASS",
|
||||
"FAT_MASS",
|
||||
"MUSCLE_MASS",
|
||||
"SKIN_TEMPERATURE",
|
||||
"PULSE_WAVE_VELOCITY",
|
||||
"VASCULAR_AGE",
|
||||
"VISCERAL_FAT",
|
||||
] as const;
|
||||
|
||||
// `\b` boundaries keep ordinary English prose untouched — "weight"
|
||||
|
||||
Reference in new issue
Block a user