fix(insights): wire grip / pain / waist / waist-to-height across web and MCP

Grip strength, pain (0–10 NRS), waist circumference, and waist-to-height
existed in the measurement enum, signal registry, and FHIR export but had
no web entry, no detail page, single non-sex-aware bands, and a split-brain
MCP exposure. This closes those gaps.

Web capture: the four signals join the manual measurement form, so a
web-only self-hoster can log them (the iOS client and the measurements API
already could).

Detail pages: flip detailPage on for the four signals and mount each on the
shared HealthKit metric template (chart, stat strip, Coach-read strip,
assessment card) via routed sub-pages and tab-strip pills, the same detail
spine every other metric carries.

Sex-aware bands: grip strength (EWGSOP2 men 27 / women 16 kg) and waist
(WHO men 94 / women 80 cm) now classify by the profile sex through the
age/sex norm resolver the assessment already threads; the resolver also
returns a sex-specific, age-independent band when no date of birth is set.
Fix the waist-to-height boundary so the NICE >= 0.5 rule is correct (the
last in-range value is 0.49).

MCP single source of truth: decouple the registry mcp facet from the Coach
snapshot — a signal can be MCP-readable without being on the Coach surface.
Mark the four physical signals mcp:true, derive the MCP rich-reads clinical
set from the registry flag instead of a duplicate allowlist, and relax the
invariant to coachSnapshot implies mcp (not the reverse). PHQ-9 / GAD-7 and
the environmental signals stay mcp:false and unreachable. compare_metric and
detect_changepoints now advertise clinical-signal support to match
get_metric_baseline.
This commit is contained in:
Marc-André Bombeck committed 2026-06-28 18:33:53 +02:00
1 parent 4f39058629
commit a69697b50f
25 files changed
+726 -62

No files matched your search

+51 -1
View File
@@ -582,7 +582,9 @@
"typeGripStrength": "Griffstärke",
"typePainNrs": "Schmerz (0–10)",
"typeWaistCircumference": "Taillenumfang",
"typeWaistToHeight": "Taille-Größe-Verhältnis"
"typeWaistToHeight": "Taille-Größe-Verhältnis",
"unitScore": "Pkt.",
"unitRatio": "Verhältnis"
},
"mood": {
"title": "Stimmung",
@@ -3705,6 +3707,54 @@
"statusBelow": "unter dem Bereich",
"statusAbove": "über dem Bereich",
"directionFlat": "keine Änderung"
},
"navGripStrength": "Griffkraft",
"navPainNrs": "Schmerz",
"navWaistCircumference": "Taille",
"navWaistToHeight": "Taille/Größe",
"gripStrength": {
"title": "Griffkraft",
"description": "Maximale Handgriffkraft — ein robuster Stellvertreter für die Ganzkörperkraft. Unter dem geschlechtsspezifischen Grenzwert (Männer 27 kg, Frauen 16 kg) deutet sie auf eine mögliche Sarkopenie hin; dein eigener Verlauf führt die Einschätzung.",
"chartTitle": "Griffkraft",
"emptyState": {
"title": "Noch keine Griffkraft",
"description": "Erfasse einen Wert mit einem Handdynamometer — notiere den besten von mehreren Versuchen — und der Verlauf erscheint hier.",
"cta": "Griffkraft erfassen"
},
"coachPrefill": "Ich habe noch keine Griffkraft erfasst — was sagt sie über meine Muskelgesundheit aus, und wie messe und verbessere ich sie?"
},
"pain": {
"title": "Schmerz (0–10)",
"description": "Selbstberichtete Schmerzintensität auf der numerischen Skala 0–10, wobei 0 keinen Schmerz und 10 den stärksten vorstellbaren Schmerz bedeutet. Eine anhaltende Änderung um 2 Punkte ist das beobachtenswerte Signal.",
"chartTitle": "Schmerz (0–10)",
"emptyState": {
"title": "Noch keine Schmerzwerte",
"description": "Erfasse auf der Skala 0–10, wie sich dein Schmerz gerade anfühlt, und der Verlauf erscheint hier.",
"cta": "Schmerzwert erfassen"
},
"coachPrefill": "Ich habe noch keine Schmerzwerte erfasst — wie sollte ich Schmerz auf der Skala 0–10 verfolgen, und was gilt als bedeutsame Veränderung?"
},
"waist": {
"title": "Taillenumfang",
"description": "Taillenumfang in Zentimetern — ein Marker für Bauchfett. Der WHO-Grenzwert für erhöhtes Risiko ist geschlechtsspezifisch (Männer 94 cm, Frauen 80 cm); dein eigener Verlauf führt die Einschätzung.",
"chartTitle": "Taillenumfang",
"emptyState": {
"title": "Noch keine Taillenwerte",
"description": "Miss deine Taille mittig zwischen der untersten Rippe und dem Hüftknochen am Ende einer normalen Ausatmung und erfasse den Wert hier.",
"cta": "Taillenumfang erfassen"
},
"coachPrefill": "Ich habe noch keine Taillenwerte erfasst — wie messe ich meine Taille richtig, und was bedeutet der Wert für meine Gesundheit?"
},
"waistToHeight": {
"title": "Taille-zu-Größe-Verhältnis",
"description": "Deine Taille geteilt durch deine Größe — die ethnienunabhängige Einzelzahl. Sie unter 0,5 zu halten (Taille unter der halben Körpergröße) ist das einfache Ziel.",
"chartTitle": "Taille-zu-Größe-Verhältnis",
"emptyState": {
"title": "Noch kein Taille-zu-Größe-Verhältnis",
"description": "Erfasse ein Taille-zu-Größe-Verhältnis, und der Verlauf erscheint hier. Faustregel: Halte deine Taille unter der halben Körpergröße.",
"cta": "Taille-zu-Größe-Verhältnis erfassen"
},
"coachPrefill": "Ich habe noch kein Taille-zu-Größe-Verhältnis erfasst — warum ist es eine nützliche Zahl, und wie halte ich es unter 0,5?"
}
},
"thresholds": {
+51 -1
View File
@@ -582,7 +582,9 @@
"typeGripStrength": "Grip strength",
"typePainNrs": "Pain (0–10)",
"typeWaistCircumference": "Waist circumference",
"typeWaistToHeight": "Waist-to-height ratio"
"typeWaistToHeight": "Waist-to-height ratio",
"unitScore": "pts",
"unitRatio": "ratio"
},
"mood": {
"title": "Mood",
@@ -3705,6 +3707,54 @@
"statusBelow": "below range",
"statusAbove": "above range",
"directionFlat": "no change"
},
"navGripStrength": "Grip strength",
"navPainNrs": "Pain",
"navWaistCircumference": "Waist",
"navWaistToHeight": "Waist-to-height",
"gripStrength": {
"title": "Grip strength",
"description": "Maximal handgrip force — a robust proxy for whole-body strength. Below the sex-specific cut-off (men 27 kg, women 16 kg) flags probable sarcopenia; your own trend leads the read.",
"chartTitle": "Grip strength",
"emptyState": {
"title": "No grip strength yet",
"description": "Log a reading from a hand dynamometer — record the best of a few squeezes — and the trend will appear here.",
"cta": "Log grip strength"
},
"coachPrefill": "I haven't logged any grip strength yet — what does it tell me about my muscle health, and how do I measure and improve it?"
},
"pain": {
"title": "Pain (0–10)",
"description": "Patient-reported pain intensity on the 0–10 numeric rating scale, where 0 is no pain and 10 is the worst imaginable. A sustained 2-point change is the signal to watch.",
"chartTitle": "Pain (0–10)",
"emptyState": {
"title": "No pain scores yet",
"description": "Log how your pain feels right now on the 0–10 scale and the trend will appear here.",
"cta": "Log a pain score"
},
"coachPrefill": "I haven't logged any pain scores yet — how should I track pain on the 0–10 scale, and what counts as a meaningful change?"
},
"waist": {
"title": "Waist circumference",
"description": "Waist girth in centimetres — a marker of central fat. The WHO increased-risk threshold is sex-specific (men 94 cm, women 80 cm); your own trend leads the read.",
"chartTitle": "Waist circumference",
"emptyState": {
"title": "No waist measurements yet",
"description": "Measure your waist at the midpoint between the lowest rib and the hip bone, at the end of a normal breath, and log it here.",
"cta": "Log waist circumference"
},
"coachPrefill": "I haven't logged any waist measurements yet — how do I measure my waist correctly, and what does the number mean for my health?"
},
"waistToHeight": {
"title": "Waist-to-height ratio",
"description": "Your waist divided by your height — the ancestry-robust single number. Keeping it under 0.5 (waist below half your height) is the simple target.",
"chartTitle": "Waist-to-height ratio",
"emptyState": {
"title": "No waist-to-height ratio yet",
"description": "Log a waist-to-height ratio and the trend will appear here. The rule of thumb: keep your waist under half your height.",
"cta": "Log waist-to-height ratio"
},
"coachPrefill": "I haven't logged a waist-to-height ratio yet — why is it a useful number, and how do I keep it under 0.5?"
}
},
"thresholds": {
+51 -1
View File
@@ -582,7 +582,9 @@
"typeGripStrength": "Fuerza de agarre",
"typePainNrs": "Dolor (0–10)",
"typeWaistCircumference": "Perímetro de cintura",
"typeWaistToHeight": "Índice cintura-altura"
"typeWaistToHeight": "Índice cintura-altura",
"unitScore": "pts",
"unitRatio": "ratio"
},
"mood": {
"title": "Estado de ánimo",
@@ -3705,6 +3707,54 @@
"statusBelow": "por debajo del rango",
"statusAbove": "por encima del rango",
"directionFlat": "sin cambios"
},
"navGripStrength": "Fuerza de agarre",
"navPainNrs": "Dolor",
"navWaistCircumference": "Cintura",
"navWaistToHeight": "Cintura/altura",
"gripStrength": {
"title": "Fuerza de agarre",
"description": "Fuerza máxima de agarre de la mano: un indicador robusto de la fuerza de todo el cuerpo. Por debajo del umbral según el sexo (hombres 27 kg, mujeres 16 kg) indica probable sarcopenia; tu propia tendencia guía la lectura.",
"chartTitle": "Fuerza de agarre",
"emptyState": {
"title": "Aún no hay fuerza de agarre",
"description": "Registra una lectura con un dinamómetro de mano (anota el mejor de varios apretones) y la tendencia aparecerá aquí.",
"cta": "Registrar fuerza de agarre"
},
"coachPrefill": "Aún no he registrado la fuerza de agarre: ¿qué dice sobre mi salud muscular y cómo la mido y la mejoro?"
},
"pain": {
"title": "Dolor (0–10)",
"description": "Intensidad del dolor referida por el paciente en la escala numérica 0–10, donde 0 es sin dolor y 10 el peor imaginable. Un cambio sostenido de 2 puntos es la señal a vigilar.",
"chartTitle": "Dolor (0–10)",
"emptyState": {
"title": "Aún no hay puntuaciones de dolor",
"description": "Registra cómo sientes el dolor ahora mismo en la escala 0–10 y la tendencia aparecerá aquí.",
"cta": "Registrar una puntuación de dolor"
},
"coachPrefill": "Aún no he registrado puntuaciones de dolor: ¿cómo debo seguir el dolor en la escala 0–10 y qué cuenta como un cambio significativo?"
},
"waist": {
"title": "Perímetro de cintura",
"description": "Perímetro de la cintura en centímetros: un marcador de grasa central. El umbral de riesgo aumentado de la OMS depende del sexo (hombres 94 cm, mujeres 80 cm); tu propia tendencia guía la lectura.",
"chartTitle": "Perímetro de cintura",
"emptyState": {
"title": "Aún no hay medidas de cintura",
"description": "Mide tu cintura en el punto medio entre la costilla más baja y el hueso de la cadera, al final de una espiración normal, y regístrala aquí.",
"cta": "Registrar perímetro de cintura"
},
"coachPrefill": "Aún no he registrado medidas de cintura: ¿cómo mido la cintura correctamente y qué significa el número para mi salud?"
},
"waistToHeight": {
"title": "Índice cintura-altura",
"description": "Tu cintura dividida por tu altura: el número único más robusto entre poblaciones. Mantenerlo por debajo de 0,5 (cintura menor que la mitad de tu altura) es el objetivo sencillo.",
"chartTitle": "Índice cintura-altura",
"emptyState": {
"title": "Aún no hay índice cintura-altura",
"description": "Registra un índice cintura-altura y la tendencia aparecerá aquí. Regla práctica: mantén tu cintura por debajo de la mitad de tu altura.",
"cta": "Registrar índice cintura-altura"
},
"coachPrefill": "Aún no he registrado un índice cintura-altura: ¿por qué es un número útil y cómo lo mantengo por debajo de 0,5?"
}
},
"thresholds": {
+51 -1
View File
@@ -582,7 +582,9 @@
"typeGripStrength": "Force de préhension",
"typePainNrs": "Douleur (0–10)",
"typeWaistCircumference": "Tour de taille",
"typeWaistToHeight": "Rapport taille-taille"
"typeWaistToHeight": "Rapport taille-taille",
"unitScore": "pts",
"unitRatio": "ratio"
},
"mood": {
"title": "Humeur",
@@ -3705,6 +3707,54 @@
"statusBelow": "sous la plage",
"statusAbove": "au-dessus de la plage",
"directionFlat": "aucun changement"
},
"navGripStrength": "Force de préhension",
"navPainNrs": "Douleur",
"navWaistCircumference": "Tour de taille",
"navWaistToHeight": "Taille/hauteur",
"gripStrength": {
"title": "Force de préhension",
"description": "Force maximale de préhension de la main : un indicateur robuste de la force corporelle globale. Sous le seuil selon le sexe (hommes 27 kg, femmes 16 kg), elle signale une sarcopénie probable ; votre propre tendance guide la lecture.",
"chartTitle": "Force de préhension",
"emptyState": {
"title": "Pas encore de force de préhension",
"description": "Enregistrez une mesure avec un dynamomètre à main (notez le meilleur de plusieurs serrages) et la tendance apparaîtra ici.",
"cta": "Enregistrer la force de préhension"
},
"coachPrefill": "Je n'ai pas encore enregistré de force de préhension — que dit-elle sur ma santé musculaire, et comment la mesurer et l'améliorer ?"
},
"pain": {
"title": "Douleur (0–10)",
"description": "Intensité de la douleur rapportée par le patient sur l'échelle numérique 0–10, où 0 signifie aucune douleur et 10 la pire imaginable. Une variation soutenue de 2 points est le signal à surveiller.",
"chartTitle": "Douleur (0–10)",
"emptyState": {
"title": "Pas encore de scores de douleur",
"description": "Enregistrez votre douleur actuelle sur l'échelle 0–10 et la tendance apparaîtra ici.",
"cta": "Enregistrer un score de douleur"
},
"coachPrefill": "Je n'ai pas encore enregistré de score de douleur — comment suivre la douleur sur l'échelle 0–10, et qu'est-ce qu'un changement significatif ?"
},
"waist": {
"title": "Tour de taille",
"description": "Tour de taille en centimètres : un marqueur de la graisse abdominale. Le seuil de risque accru de l'OMS dépend du sexe (hommes 94 cm, femmes 80 cm) ; votre propre tendance guide la lecture.",
"chartTitle": "Tour de taille",
"emptyState": {
"title": "Pas encore de mesures de tour de taille",
"description": "Mesurez votre tour de taille à mi-chemin entre la dernière côte et l'os de la hanche, en fin d'expiration normale, et enregistrez-le ici.",
"cta": "Enregistrer le tour de taille"
},
"coachPrefill": "Je n'ai pas encore enregistré de tour de taille — comment le mesurer correctement, et que signifie ce chiffre pour ma santé ?"
},
"waistToHeight": {
"title": "Rapport taille-hauteur",
"description": "Votre tour de taille divisé par votre taille : le nombre unique le plus robuste selon les populations. Le maintenir sous 0,5 (tour de taille inférieur à la moitié de votre taille) est l'objectif simple.",
"chartTitle": "Rapport taille-hauteur",
"emptyState": {
"title": "Pas encore de rapport taille-hauteur",
"description": "Enregistrez un rapport taille-hauteur et la tendance apparaîtra ici. Règle simple : gardez votre tour de taille sous la moitié de votre taille.",
"cta": "Enregistrer le rapport taille-hauteur"
},
"coachPrefill": "Je n'ai pas encore enregistré de rapport taille-hauteur — pourquoi est-ce un chiffre utile, et comment le maintenir sous 0,5 ?"
}
},
"thresholds": {
+51 -1
View File
@@ -582,7 +582,9 @@
"typeGripStrength": "Forza di presa",
"typePainNrs": "Dolore (0–10)",
"typeWaistCircumference": "Circonferenza vita",
"typeWaistToHeight": "Rapporto vita-altezza"
"typeWaistToHeight": "Rapporto vita-altezza",
"unitScore": "pti",
"unitRatio": "rapporto"
},
"mood": {
"title": "Umore",
@@ -3705,6 +3707,54 @@
"statusBelow": "sotto l'intervallo",
"statusAbove": "sopra l'intervallo",
"directionFlat": "nessuna variazione"
},
"navGripStrength": "Forza di presa",
"navPainNrs": "Dolore",
"navWaistCircumference": "Vita",
"navWaistToHeight": "Vita/altezza",
"gripStrength": {
"title": "Forza di presa",
"description": "Forza massima di presa della mano: un indicatore robusto della forza di tutto il corpo. Sotto la soglia specifica per sesso (uomini 27 kg, donne 16 kg) segnala una probabile sarcopenia; il tuo andamento personale guida la lettura.",
"chartTitle": "Forza di presa",
"emptyState": {
"title": "Ancora nessuna forza di presa",
"description": "Registra una misura con un dinamometro manuale (annota la migliore di alcune strette) e l'andamento apparirà qui.",
"cta": "Registra la forza di presa"
},
"coachPrefill": "Non ho ancora registrato la forza di presa — cosa dice sulla salute dei miei muscoli e come la misuro e la miglioro?"
},
"pain": {
"title": "Dolore (0–10)",
"description": "Intensità del dolore riferita dal paziente sulla scala numerica 0–10, dove 0 è nessun dolore e 10 il peggiore immaginabile. Una variazione costante di 2 punti è il segnale da osservare.",
"chartTitle": "Dolore (0–10)",
"emptyState": {
"title": "Ancora nessun punteggio del dolore",
"description": "Registra come senti il dolore in questo momento sulla scala 0–10 e l'andamento apparirà qui.",
"cta": "Registra un punteggio del dolore"
},
"coachPrefill": "Non ho ancora registrato punteggi del dolore — come dovrei monitorare il dolore sulla scala 0–10 e cosa conta come variazione significativa?"
},
"waist": {
"title": "Circonferenza vita",
"description": "Circonferenza della vita in centimetri: un marcatore del grasso addominale. La soglia di rischio aumentato dell'OMS dipende dal sesso (uomini 94 cm, donne 80 cm); il tuo andamento personale guida la lettura.",
"chartTitle": "Circonferenza vita",
"emptyState": {
"title": "Ancora nessuna misura della vita",
"description": "Misura la vita nel punto medio tra l'ultima costola e l'osso dell'anca, a fine espirazione normale, e registrala qui.",
"cta": "Registra la circonferenza vita"
},
"coachPrefill": "Non ho ancora registrato misure della vita — come misuro la vita correttamente e cosa significa il numero per la mia salute?"
},
"waistToHeight": {
"title": "Rapporto vita-altezza",
"description": "La tua vita divisa per la tua altezza: il singolo numero più robusto tra le popolazioni. Tenerlo sotto 0,5 (vita inferiore alla metà dell'altezza) è l'obiettivo semplice.",
"chartTitle": "Rapporto vita-altezza",
"emptyState": {
"title": "Ancora nessun rapporto vita-altezza",
"description": "Registra un rapporto vita-altezza e l'andamento apparirà qui. Regola pratica: tieni la vita sotto la metà della tua altezza.",
"cta": "Registra il rapporto vita-altezza"
},
"coachPrefill": "Non ho ancora registrato un rapporto vita-altezza — perché è un numero utile e come lo tengo sotto 0,5?"
}
},
"thresholds": {
+51 -1
View File
@@ -582,7 +582,9 @@
"typeGripStrength": "Siła chwytu",
"typePainNrs": "Ból (0–10)",
"typeWaistCircumference": "Obwód talii",
"typeWaistToHeight": "Stosunek talii do wzrostu"
"typeWaistToHeight": "Stosunek talii do wzrostu",
"unitScore": "pkt",
"unitRatio": "stosunek"
},
"mood": {
"title": "Nastrój",
@@ -3705,6 +3707,54 @@
"statusBelow": "poniżej zakresu",
"statusAbove": "powyżej zakresu",
"directionFlat": "bez zmian"
},
"navGripStrength": "Siła chwytu",
"navPainNrs": "Ból",
"navWaistCircumference": "Talia",
"navWaistToHeight": "Talia/wzrost",
"gripStrength": {
"title": "Siła chwytu",
"description": "Maksymalna siła chwytu dłoni — solidny wskaźnik ogólnej siły ciała. Poniżej progu zależnego od płci (mężczyźni 27 kg, kobiety 16 kg) sygnalizuje prawdopodobną sarkopenię; odczyt prowadzi Twój własny trend.",
"chartTitle": "Siła chwytu",
"emptyState": {
"title": "Brak pomiarów siły chwytu",
"description": "Zapisz pomiar z dynamometru ręcznego (zanotuj najlepszy z kilku ściśnięć), a trend pojawi się tutaj.",
"cta": "Zapisz siłę chwytu"
},
"coachPrefill": "Nie zapisałem jeszcze siły chwytu — co mówi o zdrowiu moich mięśni i jak ją zmierzyć oraz poprawić?"
},
"pain": {
"title": "Ból (0–10)",
"description": "Zgłaszana przez pacjenta intensywność bólu w skali numerycznej 0–10, gdzie 0 to brak bólu, a 10 najgorszy wyobrażalny. Utrzymująca się zmiana o 2 punkty to sygnał do obserwacji.",
"chartTitle": "Ból (0–10)",
"emptyState": {
"title": "Brak ocen bólu",
"description": "Zapisz, jak odczuwasz ból teraz, w skali 0–10, a trend pojawi się tutaj.",
"cta": "Zapisz ocenę bólu"
},
"coachPrefill": "Nie zapisałem jeszcze ocen bólu — jak śledzić ból w skali 0–10 i co liczy się jako istotna zmiana?"
},
"waist": {
"title": "Obwód talii",
"description": "Obwód talii w centymetrach — wskaźnik tłuszczu brzusznego. Próg zwiększonego ryzyka WHO zależy od płci (mężczyźni 94 cm, kobiety 80 cm); odczyt prowadzi Twój własny trend.",
"chartTitle": "Obwód talii",
"emptyState": {
"title": "Brak pomiarów talii",
"description": "Zmierz talię w połowie odległości między najniższym żebrem a kością biodrową, na końcu normalnego wydechu, i zapisz tutaj.",
"cta": "Zapisz obwód talii"
},
"coachPrefill": "Nie zapisałem jeszcze pomiarów talii — jak prawidłowo zmierzyć talię i co oznacza ta liczba dla mojego zdrowia?"
},
"waistToHeight": {
"title": "Stosunek talii do wzrostu",
"description": "Twoja talia podzielona przez wzrost — najbardziej uniwersalna pojedyncza liczba. Utrzymanie go poniżej 0,5 (talia mniejsza niż połowa wzrostu) to prosty cel.",
"chartTitle": "Stosunek talii do wzrostu",
"emptyState": {
"title": "Brak stosunku talii do wzrostu",
"description": "Zapisz stosunek talii do wzrostu, a trend pojawi się tutaj. Zasada: utrzymuj talię poniżej połowy wzrostu.",
"cta": "Zapisz stosunek talii do wzrostu"
},
"coachPrefill": "Nie zapisałem jeszcze stosunku talii do wzrostu — dlaczego to przydatna liczba i jak utrzymać ją poniżej 0,5?"
}
},
"thresholds": {