Files
HealthLog/tests/integration/__golden__/status-parity/metric.json
T
Marc-André Bombeck 73cee35917 fix(ai): bound one completion call to two requests
A gateway that refuses reasoning_effort outright (LiteLLM in front of
Ollama: "does not support parameters: ['reasoning_effort']") in front of a
model that reasons without answering sent requests until something outside
stopped it. The answerless rule learned to ask with "none", the refusal of
that "none" was learned as "send no field" over it, the next request came
back answerless again, and each lesson undid the other.

Each call of the Local and the OpenAI-compatible gateway clients now carries
one request budget through every repeat (request-hops.ts): at most two
requests, after which the call ends with the failure it has. A structural
guard holds both clients to sending only through the budget and to handing
it to every repeat.

The refusal is now learned as what it is: an endpoint that refuses the
field, in front of a model already seen reasoning unasked, keeps both facts
(FIELD_REFUSED_REASONS_REGARDLESS), so it is never asked with "none" again
and keeps its thinking room. An answerless reply from an endpoint that
refuses the field is final. When the refused "none" was the repeat of an
answerless reply, the call fails as reasoning_only, which is what it ran
into. The refusal handling of both clients lives in wire-refusal.ts.

A status run that hits its bound now aborts the call it gave up on instead
of leaving it running detached.

Refs #1279
2026-10-25 00:11:42 +02:00

6165 lines
462 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"BLOOD_GLUCOSE bare-error-de": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
},
"BLOOD_GLUCOSE bare-error-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
},
"BLOOD_GLUCOSE blocked-es": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with the direction of change over time, then say where it stands now.",
"Write one short assessment of this person's blood glucose. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der Konstanz bzw. Streuung der Werte eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 35 Tages-Buckets im Fenster, letzter Wert heute.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Cuando la glucosa en sangre es mayor, la frecuencia cardíaca en reposo del día siguiente parece tender a subir, según los datos disponibles. Es un patrón que conviene observar, no una causa. (n=34, r=0.94)",
"- Cuando la glucosa en sangre es mayor, la presión sistólica del día siguiente parece tender a subir, según los datos disponibles. Es un patrón que conviene observar, no una causa. (n=23, r=0.91)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"{\"locale\":\"es\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"BLOOD_GLUCOSE\",\"metric\":{\"id\":\"BLOOD_GLUCOSE\",\"displayName\":\"Blood glucose\",\"unit\":\"mmol/L\",\"direction\":\"target-band\",\"normalRange\":{\"low\":3.9,\"high\":7.8}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":35,\"totalSpanDays\":136,\"newestMeasurementDaysAgo\":0},\"BLOOD_GLUCOSE\":{\"signal\":{\"metric\":\"Blood glucose\",\"unit\":\"mmol/L\",\"current\":5.56,\"currentWindowDays\":6,\"baseline\":5.67,\"baselineLabel\":\"your monthly average\",\"delta\":-0.11,\"deltaPct\":-2,\"spread\":0.31,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":6,\"newestDaysAgo\":0,\"normalRange\":{\"low\":3.9,\"high\":7.8},\"placement\":\"in band\"},\"summary\":{\"points\":35,\"start\":5.3,\"end\":6,\"delta\":0.7,\"mean\":5.47,\"min\":4.8,\"max\":6},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"date\":\"2026-05-30\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"date\":\"2026-06-03\",\"min\":5.66,\"max\":5.66,\"mean\":5.66,\"n\":1},{\"date\":\"2026-06-07\",\"min\":5.94,\"max\":5.94,\"mean\":5.94,\"n\":1},{\"date\":\"2026-06-11\",\"min\":5.88,\"max\":5.88,\"mean\":5.88,\"n\":1},{\"date\":\"2026-06-15\",\"min\":5.33,\"max\":5.33,\"mean\":5.33,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W13\",\"min\":4.88,\"max\":5.27,\"mean\":5.08,\"n\":2},{\"weekISO\":\"2026-W14\",\"min\":5.77,\"max\":5.83,\"mean\":5.8,\"n\":2},{\"weekISO\":\"2026-W15\",\"min\":5.66,\"max\":5.88,\"mean\":5.77,\"n\":2},{\"weekISO\":\"2026-W16\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W17\",\"min\":4.94,\"max\":5.16,\"mean\":5.05,\"n\":2},{\"weekISO\":\"2026-W18\",\"min\":5.22,\"max\":5.72,\"mean\":5.47,\"n\":2},{\"weekISO\":\"2026-W19\",\"min\":5.72,\"max\":6.05,\"mean\":5.88,\"n\":2},{\"weekISO\":\"2026-W20\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"weekISO\":\"2026-W21\",\"min\":4.83,\"max\":5.22,\"mean\":5.02,\"n\":2}],\"monthly\":[{\"month\":\"2026-01\",\"min\":5.99,\"max\":5.99,\"mean\":5.99,\"n\":1},{\"month\":\"2026-02\",\"min\":4.88,\"max\":5.83,\"mean\":5.37,\"n\":7},{\"month\":\"2026-03\",\"min\":5.22,\"max\":5.99,\"mean\":5.65,\"n\":4}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":5.3}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in Spanish: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Blood glucose (unit: mmol/L).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 3.9–7.8 mmol/L (a placement aid only — the user's OWN baseline leads).",
"",
"OUTPUT LANGUAGE: Responda en español (registro peninsular formal — usted). Use un vocabulario sanitario en español natural."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Estable, como de costumbre. Blood glucose está en 5,6 mmol/L ahora mismo — por debajo de tu promedio habitual de 5,7 mmol/L. Eso queda dentro de tu rango habitual — nada que pida una reacción ahora.",
"updatedAt": null
}
},
"BLOOD_GLUCOSE cached-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"BLOOD_GLUCOSE forced-unchanged-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"BLOOD_GLUCOSE fresh-en": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with the direction of change over time, then say where it stands now.",
"Write one short assessment of this person's blood glucose. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"VARIETY: to keep your cards from reading the same, you may open this one by leading with how consistent or variable the readings have been — only if the data genuinely supports that angle; never force it, never invent a trend.",
"",
"DATA STRENGTH: 35 day-buckets in the window, latest reading today.",
"",
"RELATIONS (statistically-screened associations in YOUR data involving this metric — descriptive, NEVER causal):",
"- Higher blood glucose looks like it goes with higher next-day resting heart rate in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=34, r=0.94)",
"- Higher blood glucose looks like it goes with higher next-day systolic blood pressure in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=23, r=0.91)",
"You MAY weave at most ONE of these in if it adds genuine insight, phrased as an \"association\" / \"tends to go with\" — never as a cause, and never alter the numbers. Skip them if the metric's own finding is the stronger story.",
"",
"",
"{\"locale\":\"en\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"BLOOD_GLUCOSE\",\"metric\":{\"id\":\"BLOOD_GLUCOSE\",\"displayName\":\"Blood glucose\",\"unit\":\"mmol/L\",\"direction\":\"target-band\",\"normalRange\":{\"low\":3.9,\"high\":7.8}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":35,\"totalSpanDays\":136,\"newestMeasurementDaysAgo\":0},\"BLOOD_GLUCOSE\":{\"signal\":{\"metric\":\"Blood glucose\",\"unit\":\"mmol/L\",\"current\":5.56,\"currentWindowDays\":6,\"baseline\":5.67,\"baselineLabel\":\"your monthly average\",\"delta\":-0.11,\"deltaPct\":-2,\"spread\":0.31,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":6,\"newestDaysAgo\":0,\"normalRange\":{\"low\":3.9,\"high\":7.8},\"placement\":\"in band\"},\"summary\":{\"points\":35,\"start\":5.3,\"end\":6,\"delta\":0.7,\"mean\":5.47,\"min\":4.8,\"max\":6},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"date\":\"2026-05-30\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"date\":\"2026-06-03\",\"min\":5.66,\"max\":5.66,\"mean\":5.66,\"n\":1},{\"date\":\"2026-06-07\",\"min\":5.94,\"max\":5.94,\"mean\":5.94,\"n\":1},{\"date\":\"2026-06-11\",\"min\":5.88,\"max\":5.88,\"mean\":5.88,\"n\":1},{\"date\":\"2026-06-15\",\"min\":5.33,\"max\":5.33,\"mean\":5.33,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W13\",\"min\":4.88,\"max\":5.27,\"mean\":5.08,\"n\":2},{\"weekISO\":\"2026-W14\",\"min\":5.77,\"max\":5.83,\"mean\":5.8,\"n\":2},{\"weekISO\":\"2026-W15\",\"min\":5.66,\"max\":5.88,\"mean\":5.77,\"n\":2},{\"weekISO\":\"2026-W16\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W17\",\"min\":4.94,\"max\":5.16,\"mean\":5.05,\"n\":2},{\"weekISO\":\"2026-W18\",\"min\":5.22,\"max\":5.72,\"mean\":5.47,\"n\":2},{\"weekISO\":\"2026-W19\",\"min\":5.72,\"max\":6.05,\"mean\":5.88,\"n\":2},{\"weekISO\":\"2026-W20\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"weekISO\":\"2026-W21\",\"min\":4.83,\"max\":5.22,\"mean\":5.02,\"n\":2}],\"monthly\":[{\"month\":\"2026-01\",\"min\":5.99,\"max\":5.99,\"mean\":5.99,\"n\":1},{\"month\":\"2026-02\",\"min\":4.88,\"max\":5.83,\"mean\":5.37,\"n\":7},{\"month\":\"2026-03\",\"min\":5.22,\"max\":5.99,\"mean\":5.65,\"n\":4}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":5.3}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in English: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Blood glucose (unit: mmol/L).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 3.9–7.8 mmol/L (a placement aid only — the user's OWN baseline leads)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"BLOOD_GLUCOSE keyless-de": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Stabil und wie gewohnt. Blood glucose liegt aktuell bei 100 mg/dL — niedriger als dein üblicher Schnitt von 102 mg/dL. Das ist in deinem gewohnten Rahmen — nichts, worauf du jetzt reagieren musst.",
"updatedAt": null
}
},
"BLOOD_GLUCOSE keyless-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Steady and much as usual. Blood glucose is at 100 mg/dL right now — lower than your usual average of 102 mg/dL. That sits in your usual range — nothing you need to act on right now.",
"updatedAt": null
}
},
"BLOOD_GLUCOSE keyless-read-only": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "No assessment on this one right now. These numbers become readable across several weeks rather than single days, and taken at consistent times so they stay comparable. The signal that counts is several metrics drifting the same unfavourable way at once, not one value on one day.",
"updatedAt": null
}
},
"BLOOD_GLUCOSE next-day-en": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-16",
"OPENER HINT: Open by contrasting now against the user's own baseline.",
"Write one short assessment of this person's blood glucose. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS (1 day ago, 2026-06-15):",
"Parity note for fresh-en.",
"",
"INSTRUCTION: When summarising the current state, explicitly call out what improved, what regressed, and what stayed the same compared to that previous snapshot. Use phrases like \"down 4 mmHg from your last check\" or \"same elevated trend as last week\". Do not invent numbers — only compare what's in the snapshot below.",
"",
"",
"VARIETY: to keep your cards from reading the same, you may open this one by leading with the recent direction of travel (rising / falling / flat vs the baseline) — only if the data genuinely supports that angle; never force it, never invent a trend.",
"",
"DATA STRENGTH: 35 day-buckets in the window, latest reading 1 day ago.",
"",
"RELATIONS (statistically-screened associations in YOUR data involving this metric — descriptive, NEVER causal):",
"- Higher blood glucose looks like it goes with higher next-day resting heart rate in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=34, r=0.94)",
"- Higher blood glucose looks like it goes with higher next-day systolic blood pressure in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=23, r=0.91)",
"You MAY weave at most ONE of these in if it adds genuine insight, phrased as an \"association\" / \"tends to go with\" — never as a cause, and never alter the numbers. Skip them if the metric's own finding is the stronger story.",
"",
"",
"{\"locale\":\"en\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-16\",\"focus\":\"BLOOD_GLUCOSE\",\"metric\":{\"id\":\"BLOOD_GLUCOSE\",\"displayName\":\"Blood glucose\",\"unit\":\"mmol/L\",\"direction\":\"target-band\",\"normalRange\":{\"low\":3.9,\"high\":7.8}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":35,\"totalSpanDays\":136,\"newestMeasurementDaysAgo\":1},\"BLOOD_GLUCOSE\":{\"signal\":{\"metric\":\"Blood glucose\",\"unit\":\"mmol/L\",\"current\":5.66,\"currentWindowDays\":5,\"baseline\":5.67,\"baselineLabel\":\"your monthly average\",\"delta\":-0.01,\"deltaPct\":-0.2,\"spread\":0.31,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":5,\"newestDaysAgo\":1,\"normalRange\":{\"low\":3.9,\"high\":7.8},\"placement\":\"in band\"},\"summary\":{\"points\":35,\"start\":5.3,\"end\":6,\"delta\":0.7,\"mean\":5.47,\"min\":4.8,\"max\":6},\"series\":{\"recent\":[{\"date\":\"2026-05-30\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"date\":\"2026-06-03\",\"min\":5.66,\"max\":5.66,\"mean\":5.66,\"n\":1},{\"date\":\"2026-06-07\",\"min\":5.94,\"max\":5.94,\"mean\":5.94,\"n\":1},{\"date\":\"2026-06-11\",\"min\":5.88,\"max\":5.88,\"mean\":5.88,\"n\":1},{\"date\":\"2026-06-15\",\"min\":5.33,\"max\":5.33,\"mean\":5.33,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W13\",\"min\":4.88,\"max\":5.27,\"mean\":5.08,\"n\":2},{\"weekISO\":\"2026-W14\",\"min\":5.77,\"max\":5.83,\"mean\":5.8,\"n\":2},{\"weekISO\":\"2026-W15\",\"min\":5.66,\"max\":5.88,\"mean\":5.77,\"n\":2},{\"weekISO\":\"2026-W16\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W17\",\"min\":4.94,\"max\":5.16,\"mean\":5.05,\"n\":2},{\"weekISO\":\"2026-W18\",\"min\":5.22,\"max\":5.72,\"mean\":5.47,\"n\":2},{\"weekISO\":\"2026-W19\",\"min\":5.72,\"max\":6.05,\"mean\":5.88,\"n\":2},{\"weekISO\":\"2026-W20\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"weekISO\":\"2026-W21\",\"min\":4.83,\"max\":5.22,\"mean\":5.02,\"n\":2},{\"weekISO\":\"2026-W22\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1}],\"monthly\":[{\"month\":\"2026-01\",\"min\":5.99,\"max\":5.99,\"mean\":5.99,\"n\":1},{\"month\":\"2026-02\",\"min\":4.88,\"max\":5.83,\"mean\":5.37,\"n\":7},{\"month\":\"2026-03\",\"min\":5.22,\"max\":5.99,\"mean\":5.65,\"n\":4}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":1,\"value\":5.3}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in English: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Blood glucose (unit: mmol/L).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 3.9–7.8 mmol/L (a placement aid only — the user's OWN baseline leads)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Parity note for next-day-en.",
"updatedAt": "2026-06-16T10:00:00.000Z"
}
},
"BLOOD_GLUCOSE prose-de": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Datum: 2026-06-15",
"OPENER HINT: Eröffne mit der Richtung der Veränderung über die Zeit und nenne dann den aktuellen Stand.",
"Schreibe eine kurze Einschätzung zu Blood glucose dieser Person. Beginne mit der BEDEUTUNG in klaren Worten — dem Eindruck, nicht der Zahl (z. B. \"läuft gerade etwas ruhiger als sonst\", \"stabil und genau da, wo es war\") — und bring danach EINE konkrete Zahl aus dem Snapshot als Beleg, gegen die eigene Wochen-/Monats-Baseline eingeordnet; führe nie mit dem Wert. Schließe nur dann mit einem machbaren Schritt, wenn der Befund wirklich einen hergibt; ist nichts umsetzbar, lass den Schritt weg statt Fülltext zu erfinden. Konfidenz aus Messanzahl und Aktualität ableiten.",
"",
"VORHERIGE ANALYSE: keine vorhanden. Behandle dies als erste Analyse in diesem Bereich — kein Verbesserungs-/Verschlechterungs-Delta zu nennen.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der Konstanz bzw. Streuung der Werte eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 35 Tages-Buckets im Fenster, letzter Wert heute.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Wenn der Blutzucker höher liegt, scheint die Ruheherzfrequenz am Folgetag nach bisheriger Datenlage eher höher auszufallen. Das ist ein Muster, das Beachtung verdient, keine Ursache. (n=34, r=0.94)",
"- Wenn der Blutzucker höher liegt, scheint der systolische Blutdruck am Folgetag nach bisheriger Datenlage eher höher auszufallen. Das ist ein Muster, das Beachtung verdient, keine Ursache. (n=23, r=0.91)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"{\"locale\":\"de\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"BLOOD_GLUCOSE\",\"metric\":{\"id\":\"BLOOD_GLUCOSE\",\"displayName\":\"Blood glucose\",\"unit\":\"mmol/L\",\"direction\":\"target-band\",\"normalRange\":{\"low\":3.9,\"high\":7.8}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":35,\"totalSpanDays\":136,\"newestMeasurementDaysAgo\":0},\"BLOOD_GLUCOSE\":{\"signal\":{\"metric\":\"Blood glucose\",\"unit\":\"mmol/L\",\"current\":5.56,\"currentWindowDays\":6,\"baseline\":5.67,\"baselineLabel\":\"your monthly average\",\"delta\":-0.11,\"deltaPct\":-2,\"spread\":0.31,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":6,\"newestDaysAgo\":0,\"normalRange\":{\"low\":3.9,\"high\":7.8},\"placement\":\"in band\"},\"summary\":{\"points\":35,\"start\":5.3,\"end\":6,\"delta\":0.7,\"mean\":5.47,\"min\":4.8,\"max\":6},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"date\":\"2026-05-30\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"date\":\"2026-06-03\",\"min\":5.66,\"max\":5.66,\"mean\":5.66,\"n\":1},{\"date\":\"2026-06-07\",\"min\":5.94,\"max\":5.94,\"mean\":5.94,\"n\":1},{\"date\":\"2026-06-11\",\"min\":5.88,\"max\":5.88,\"mean\":5.88,\"n\":1},{\"date\":\"2026-06-15\",\"min\":5.33,\"max\":5.33,\"mean\":5.33,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W13\",\"min\":4.88,\"max\":5.27,\"mean\":5.08,\"n\":2},{\"weekISO\":\"2026-W14\",\"min\":5.77,\"max\":5.83,\"mean\":5.8,\"n\":2},{\"weekISO\":\"2026-W15\",\"min\":5.66,\"max\":5.88,\"mean\":5.77,\"n\":2},{\"weekISO\":\"2026-W16\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W17\",\"min\":4.94,\"max\":5.16,\"mean\":5.05,\"n\":2},{\"weekISO\":\"2026-W18\",\"min\":5.22,\"max\":5.72,\"mean\":5.47,\"n\":2},{\"weekISO\":\"2026-W19\",\"min\":5.72,\"max\":6.05,\"mean\":5.88,\"n\":2},{\"weekISO\":\"2026-W20\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"weekISO\":\"2026-W21\",\"min\":4.83,\"max\":5.22,\"mean\":5.02,\"n\":2}],\"monthly\":[{\"month\":\"2026-01\",\"min\":5.99,\"max\":5.99,\"mean\":5.99,\"n\":1},{\"month\":\"2026-02\",\"min\":4.88,\"max\":5.83,\"mean\":5.37,\"n\":7},{\"month\":\"2026-03\",\"min\":5.22,\"max\":5.99,\"mean\":5.65,\"n\":4}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":5.3}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"Du schreibst eine kurze, persönliche Einschätzung zu EINER Gesundheitsmetrik dieses Nutzers. Du kennst seine Daten und ordnest sie gegen seine EIGENE Baseline ein — nicht gegen Bevölkerungsnormen. Deine fachliche Grundlage sind anerkannte Leitlinien (ESH 2023, WHO, AASM, DGE, DEGAM); du beziehst dich darauf, ohne zu diagnostizieren.",
"",
"DEINE DATENGRUNDLAGE (graded snapshot):",
"- signal: der fertige Vergleich — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` ist das recent-Mittel; `baseline` ist der EIGENE längere Durchschnitt; `delta`/`deltaPct` sind die VORZEICHENBEHAFTETE Änderung gegenüber dieser Baseline; `spread` ist die normale Schwankung; `outsideNormalSwing` ist das vorab berechnete Urteil, ob die Änderung diese Schwankung übersteigt. Diese Werte sind bereits berechnet — nenne sie, rechne sie NICHT neu. `contributors[]` (nur Score-Komposite) benennt die 1–2 Teil-Scores, die den Score bewegt haben.",
"- summary: { points, start, end, delta, mean, min, max } — die Eckwerte des gesamten Lesefensters.",
"- series.recent[]: die jüngsten ~21 Tage, je ein Eintrag pro Tag ({ date, min, max, mean, n }).",
"- series.weekly[]: die ~10 Wochen davor, je ein ISO-Wochen-Aggregat.",
"- series.monthly[]: die ~12 Monate davor, je ein Monatsaggregat.",
"- series.yearly[]: alles ältere, je ein Jahr ({ year, mean, min, max, n, slope }).",
"- Die jüngsten Tage liegen also EINZELN vor, ältere Zeiträume als Wochen-, Monats- und Jahresaggregate. Ziehe die series nur für einen konkreten Tag heran; führe sonst mit dem signal-Block.",
"- Ein Slice kann leer sein, wenn die Historie kurz ist. Dann nicht so tun, als gäbe es ihn. Ist `signal.baseline` null, gibt es noch keine etablierte Baseline; sage das ehrlich, statt einen Vergleich zu erfinden.",
"",
"SO BAUST DU DIE EINSCHÄTZUNG — wähle die 2–3 BAUSTEINE, die zu DIESEN Daten passen, und ordne sie so, dass sie als EIN zusammenhängender Gedanke lesen, keine feste Checkliste. Führe gemäß dem OPENER-HINWEIS im User-Prompt, wenn einer mitgegeben ist — eröffne NICHT immer mit der Zahl. Variiere die Form von Metrik zu Metrik; eröffne nie zwei Metriken hintereinander gleich.",
"Verfügbare Bausteine (nimm die wenigen, die wirklich zutreffen):",
"(a) der aktuelle Befund — `current` aus dem signal-Block (oder ein Wert aus series.recent für eine Tagesfrage);",
"(b) gegen die EIGENE Baseline einordnen über das vorab berechnete vorzeichenbehaftete `delta` gegenüber `baselineLabel` — nenne es, leite es nicht neu her. Behandle `outsideNormalSwing: false` als \"innerhalb der üblichen Schwankung — kein Befund\" und ERFINDE KEINEN Trend; `outsideNormalSwing: true` ist die echte, meldenswerte Änderung. Ein `normalRange`/`placement` ist nur ein grober sekundärer Anker — das persönliche delta führt;",
"(c) einen echten, verdienten Erfolg oder eine stabile Serie benennen, wenn die Daten ihn zeigen;",
"(d) einen Punkt zum Im-Auge-behalten;",
"(e) einen Zusammenhang NUR, wenn ein r-Wert vorhanden und |r| > 0,4 ist, formuliert als \"bewegt sich mit\" / \"zeigt sich oft zusammen mit\", nie kausal;",
"(f) GENAU EINEN machbaren nächsten Schritt — und nur, wenn der Befund wirklich einen hergibt. Eine Botschaft = ein Verhalten, keine Liste. Ist der Wert stabil und im grünen Bereich, ERZWINGE KEINEN Schritt — bestätige kurz und nenne stattdessen einen Punkt zum Beobachten. Ein erfundener Schritt ist genau die Floskel, die wir vermeiden.",
"Synthese statt Aufzählung: die Geschichte dessen, was die Daten bedeuten, zählt mehr als das Wiederholen jeder Zahl.",
"",
"TONALITÄT — ein warmer, motivierender Premium-Begleiter (jemand hat sich die Daten dieser Person wirklich angesehen und etwas Wertvolles für sie gefunden):",
"- Zweite Person (\"dein Blutdruck\", \"deine Werte\"), warm, direkt, ehrlich.",
"- Motivierend und vorwärtsgewandt: Wenn die Daten es hergeben, benenne den echten Erfolg klar und baue ein wenig Schwung auf — die Person soll sich gesehen und unterstützt fühlen, nicht belehrt. Die Ermutigung muss durch die Zahlen VERDIENT sein, nie ein reflexhaftes Kompliment.",
"- Autonomie-unterstützend: \"kann helfen\", \"einen Versuch wert\", nie \"du musst\".",
"- Nie alarmierend, nie moralisierend, nie diagnostisch — keine Krankheitsbehauptung. Formuliere als begründete Beobachtung, nicht als ärztlichen Rat.",
"- Auch ungünstige Werte ehrlich benennen: Befund → gegen die eigene Baseline einordnen → ein kleiner machbarer Schritt, als Chance formuliert, nicht als Versagen. Nicht verharmlosen, nicht dramatisieren.",
"- Keine Floskeln und keine bloße Zahlenwiederholung: jede warme Zeile ist an eine echte Zahl oder eine echte Veränderung geknüpft. Ein generischer Positiv-Einstieg (\"Deine Werte sehen gut aus\") ist verboten — verdiene die Ermutigung mit dem konkreten Befund.",
"",
"ERÖFFNUNG — mit der Bedeutung führen, nicht mit dem Messwert",
"Beginne mit dem Eindruck in klaren Worten — was das heute über die Person sagt — und bring die Zahl direkt danach als Beleg, nie als Erstes. Eine Zeile, die mit einem Wert eröffnet (\"Dein Ruhepuls ist 61 …\"), liest sich wie ein Ablesen; dieselbe Zeile, die mit der Bedeutung eröffnet (\"Dein Herz läuft diese Woche etwas ruhiger — rund 61 …\"), liest sich wie ein Begleiter, der wirklich hingesehen hat. Jede Aussage bleibt an einer echten Zahl verankert; nur die REIHENFOLGE ändert sich, Bedeutung zuerst und die Zahl direkt dahinter. Das gilt, ob die Fläche eine Metrik abdeckt oder viele.",
"",
"LÄNGE: 2-4 Sätze, ca. 30-60 Wörter — ist der Wert aber stabil und nichts zu tun, ist EIN knapper Satz besser, als ihn auf Länge zu strecken. Knapp und hochwertig. Keine bloße Zahlenwiederholung, kein Fülltext, keine generischen Floskeln.",
"",
"DATENLAGE EHRLICH BEWERTEN (nie einen Trend erfinden):",
"- Nur wenige Messpunkte/Einträge/Ereignisse oder ein leerer recent-Slice: ehrlich sagen, dass es für eine belastbare Tendenz noch zu wenige Daten sind, und EINEN Hinweis geben (z.B. regelmäßiger erfassen). Keinen Trend behaupten. Was \"wenige\" bedeutet, hängt von der Metrik ab — bei Stimmung sind es Einträge, bei der Einnahmetreue geplante Dosen.",
"- Jüngste Messung deutlich älter als ~7 Tage (dataCoverage.newestMeasurementDaysAgo): darauf hinweisen, dass die Werte nicht mehr aktuell sind.",
"- Korrelationen NUR erwähnen, wenn der r-Wert im Snapshot vorhanden ist und |r| > 0.4 ist. Fehlt das Feld, keine Korrelation interpretieren oder erfinden. Immer als \"Zusammenhang\" formulieren, nie als \"Ursache\".",
"",
"VERBOTENE FLOSKELN (signalisieren ungegroundeten Fülltext — nie ausgeben, außer im Disclaimer)",
"\"achte auf ausreichend Schlaf\", \"trinke genug Wasser\", \"regelmäßige Bewegung\", \"ärztlicher Rat empfohlen\".",
"",
"METRIK-IDENTIFIER GEHÖREN NICHT IN DEN FLIESSTEXT",
"Schreibe niemals Datenbank- bzw. Enum-Namen wie \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" oder \"SLEEP_DURATION\" in nutzersichtbare Strings, und schreibe nie das wörtliche \"metric:<TYPE>\"-Chart-Token in den Fließtext. Verweise auf jede Metrik mit der natürlichsprachlichen Bezeichnung, die der Nutzer sieht — \"deine Systole\", \"dein Gewicht\", \"dein Puls\", \"deine Stimmung\", \"deine Medikamentenadhärenz\", \"dein Ruhepuls\", \"deine Schlafdauer\", \"deine Schritte\".",
"",
"GLP-1-DOSIS-SICHERHEIT (Vertrag, kein Stil)",
"Verschreibe, empfiehl oder ändere NIEMALS Medikamenten-Dosen, auch wenn der Snapshot einen GLP-1-Rezeptoragonisten benennt (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). Du darfst den benannten Wirkstoff und die aktuelle Titrationsstufe NENNEN (\"Woche 3 auf 7,5 mg\"), wenn der Snapshot sie trägt, aber schreibe nie \"erhöhe auf X mg\", \"erwäge die nächste Stufe Y mg\", \"bleibe auf Z mg\" oder eine Variante davon. Ein Plateau rahmt die nächste Entscheidung immer als Gespräch mit der behandelnden Ärztin. Bist du unsicher, ob etwas dosis-präskriptiv ist, behandle es so — und verweise an die Klinik.",
"",
"AKUTE WARNZEICHEN (Vertrag, kein Stil)",
"Beschreibt der Nutzer ein akutes Krisenzeichen — Brustschmerz oder Druck auf der Brust, Ohnmacht oder Beinahe-Ohnmacht (Synkope), ein plötzliches schweres Symptom (z. B. stärkster Kopfschmerz aller Zeiten, plötzliche Schwäche oder Sprachstörung, Atemnot), einen hypertensiven Notfallwert (systolisch ≥ 180 oder diastolisch ≥ 120 mit Symptomen), einen schwer-niedrigen oder sehr hohen Glukosewert (unter 54 mg/dL (3,0 mmol/L), oder unter 70 mg/dL (3,9 mmol/L) mit Symptomen, oder ≥ 250 mg/dL (13,9 mmol/L) mit Symptomen), anhaltendes Fieber ≥ 38,5 °C (101,3 °F) oder Gedanken an Suizid bzw. Selbstverletzung — sage in einem ruhigen Satz klar, dass das jetzt umgehende ärztliche Hilfe oder den Notruf braucht, und coache es NICHT anhand der Daten. Diagnostiziere nicht, benenne keine Erkrankung, schätze keinen Schweregrad aus den Zahlen — verweise nur auf umgehende Hilfe bzw. den Notruf und höre auf. Das ist eine geschlossene Liste; außerhalb davon bleibe wie gewohnt ruhig und nicht alarmierend.",
"",
"ERDUNG — NULL HALLUZINATIONEN",
"Jede Aussage muss auf einer Zahl beruhen, die im übergebenen Snapshot sichtbar ist. Lässt sich die Aussage keinem Snapshot-Feld zuordnen, lass sie weg und erfinde nie einen Messwert, um einer Anfrage zu entsprechen. Ordne jeden Wert gegen die EIGENE Baseline des Nutzers ein (jüngeres vs. längeres Mittel), nie gegen eine Bevölkerungsnorm. Nenne einen Zusammenhang nur, wenn der r-Wert vorhanden und |r| > 0,4 ist — immer als \"Zusammenhang\", nie als \"Ursache\".",
"",
"TONALITÄT — ein warmer, motivierender Begleiter, nie klinisch oder alarmierend",
"Schreibe in der zweiten Person, warm und direkt. Wenn die Daten es hergeben, benenne den echten Erfolg klar und baue ein wenig Schwung auf — die Person soll sich gesehen und unterstützt fühlen, nicht belehrt. Die Ermutigung muss durch die Zahlen VERDIENT sein, nie ein reflexhaftes Kompliment. Lob ist verankert, konkret und angemessen: an einer echten Zahl oder Veränderung festgemacht, nicht auf andere Nutzer übertragbar, und stiller Anerkennung für stille Erfolge. Über-Bestätigung ist eine Sicherheitsregression, keine Wärme — bestätige nie einen sich verschlechternden Trend oder eine unsichere Entscheidung; würdige die Mühe, nicht die Entscheidung, und bleib neutral (\"nichts zu tun — die gute Art von langweilig\"), wenn es nichts zu loben gibt, statt ein Kompliment zu erfinden. Sei autonomie-unterstützend (\"einen Versuch wert\", \"kann helfen\", nie \"du musst\"). Benenne auch ungünstige Werte ehrlich — Befund, dann gegen die eigene Baseline einordnen, dann ein kleiner machbarer Schritt, als Chance formuliert. Nie alarmierend, nie moralisierend, nie diagnostisch. Keine Floskeln und keine bloße Zahlenwiederholung. Beginne NICHT mit einem Kompliment über Datenmenge oder -qualität; verbotene Eröffnungen sind u.a. \"Datengrundlage ist sehr stark\", \"Your data foundation is strong\", \"Du hast eine solide Baseline\", \"Großartiger Datensatz\", ein generisches \"Deine Werte sehen gut aus\" und jede sinngemäße Umformulierung.",
"",
"KEINE EINSCHÄTZUNG — nie Mechanik nacherzählen",
"Eine Messanzahl (\"3-mal erfasst\"), ein Erfassungsrhythmus (\"alle paar Tage gemessen\") oder Bedien-Mechanik ist KEINE Einschätzung und gehört für sich genommen nicht in den Text. Nutze eine solche Angabe NUR, wenn sie eine Konsequenz trägt, und nenne dann die Konsequenz, nicht die Zahl: z. B. \"diese Woche zu wenige Werte für eine Tendenz — eine Morgenmessung würde es klären\", nicht \"du hast diese Woche zweimal gemessen\". Jeder Satz muss sich verdienen, indem er sagt, was ein Wert BEDEUTET oder was daraus folgt — nie, indem er erzählt, wie die Daten erhoben wurden.",
"",
"EINORDNEN, NICHT AUFZÄHLEN",
"Sag, was ein Wert BEDEUTET, nicht nur, was er ist. Trägt der User-Prompt einen EINORDNUNGS-KONTEXT-Block, nutze ihn: benenne, wo der Wert auf der Leitlinien-Skala liegt, was dieses Band in klaren, würdevollen Worten bedeutet und was praktisch folgt. Beurteile den Trend IM KONTEXT — ein \"leicht steigender\" Wert tief in einem günstigen Band ist eine Randnotiz; dieselbe Bewegung an oder nahe einer Grenze ist die Schlagzeile. Rahme jede Konsequenz OHNE Diagnose: \"Werte in diesem Bereich gelten laut Leitlinien als …\", nie \"du hast X\" oder \"du bist gefährdet für X\". Ist KEIN Einordnungs-Block vorhanden, hat die Metrik kein allgemeines Referenzband — ordne sie gegen die EIGENE Baseline der Person ein und sage klar, dass kein allgemeines Referenzband hinterlegt ist, statt eines zu erfinden.",
"",
"FORMATIERUNG — schreibe in kurzen Absätzen, getrennt durch eine LEERZEILE, je 1–3 Sätze; eine längere Antwort hat 2–4 Absätze, nie einen Block. Setze eine Leerzeile zwischen unterschiedliche Gedanken (z. B. \"wie es steht\" vs. \"eine Sache zum Ausprobieren\"). Ein stabiler Einzeiler bleibt EIN Absatz — strecke nicht auf einen zweiten. Wenn du wirklich drei oder mehr parallele Punkte aufzählst (Optionen, Befunde, Schritte), formatiere sie als schlichte Liste: ein Punkt pro Zeile, jede Zeile beginnt mit \"- \". Die EINE wichtigste Kernaussage darfst du mit **doppelten Sternchen** fett setzen, höchstens einmal pro Antwort. Sonst nichts: keine Überschriften, kein Kursiv, keine Backticks, keine nummerierten Listen, keine Emojis.",
"",
"BEISPIELE — beachte die UNTERSCHIEDLICHEN Formen (urteil-zuerst, trend-zuerst, Einzeiler). Sie illustrieren nur Form und Erdung; übernimm sie nie — jede Einschätzung nutzt die echten Snapshot-Zahlen:",
"- URTEIL-ZUERST (Bedeutung zuerst, Zahl als Beleg, ein Schritt): \"Dein Ruhepuls läuft gerade einen Tick niedriger als sonst — diese Woche rund 61 bpm, 5 unter deinem Monatsmittel von 66 und dein niedrigster seit Wochen. So ein Rückgang passt meist zu mehr Bewegung; die Routine, die das gebracht hat, lohnt sich beizubehalten.\"",
"- TREND-ZUERST (Richtung zuerst, dann der Stand): \"Dein systolischer Blutdruck geht seit drei Wochen ruhig nach unten, aktuell rund 124 mmHg — etwa 4 unter deinem 30-Tage-Schnitt. Nichts Dramatisches, einfach eine stetige Richtung.\"",
"- EINZEILER (stabil, KEIN erzwungener Schritt): \"Deine SpO₂ ist mit 97 % stabil und genau in deinem üblichen Bereich — nichts zu tun, die gute Art von langweilig.\"",
"- SCHLECHT (verbotene Floskel, ungegroundet — so NICHT): \"Deine Werte sehen gut aus. Achte auf ausreichend Schlaf und regelmäßige Bewegung.\"",
"",
"AUSGABEFORMAT: Antworte ausschließlich mit validem JSON in genau diesem Schema. Das Feld \"summary\" enthält die komplette Einschätzung auf Deutsch: 1-3 kurze Absätze mit je 1-3 Sätzen, getrennt durch eine Leerzeile als \\n\\n INNERHALB des JSON-Strings. Ein stabiler Einzeiler bleibt EIN Absatz:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYP — PHYSIOLOGISCHER VITALWERT:",
"- Das ist ein Momentanwert. Benenne das aktuelle Niveau und ordne es sowohl gegen die eigene Baseline (recent vs. Monats-/Jahresmittel) als auch — falls ein Referenzband vorliegt — gegen dieses Band ein.",
"- Ein einzelner Wert außerhalb des Bands ist selten ein Befund; eine anhaltende Verschiebung über das recent-Fenster gegen die Baseline schon. Erwähne einen Trend außerhalb des Bands sachlich, ohne zu alarmieren.",
"- Formuliere jede Richtung (steigend/fallend) als mögliche Erklärung (Fitness, Stress, Schlaf, Krankheit, Medikament), nie als Diagnose.",
"",
"METRIK: Blood glucose (Einheit: mmol/L).",
"Kein Extrem ist gut — der Wert sollte im Normalband liegen; Abweichungen in beide Richtungen sind erwähnenswert.",
"Grobes Referenzband (Population): 3.9–7.8 mmol/L (nur Orientierung — die EIGENE Baseline führt)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Das ist kein JSON.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"BLOOD_GLUCOSE read-only-cold": {
"calls": [],
"enqueued": [
{
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"userId": "parity-rich"
}
],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"preparing": true,
"revalidating": false,
"text": null,
"updatedAt": null
}
},
"BLOOD_GLUCOSE read-only-stale": {
"calls": [],
"enqueued": [
{
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"userId": "parity-rich"
}
],
"notes": [
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"preparing": false,
"revalidating": true,
"text": "Parity note for next-day-en.",
"updatedAt": "2026-06-16T10:00:00.000Z"
}
},
"BLOOD_GLUCOSE unparseable-fr": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with the direction of change over time, then say where it stands now.",
"Write one short assessment of this person's blood glucose. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der Konstanz bzw. Streuung der Werte eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 35 Tages-Buckets im Fenster, letzter Wert heute.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Quand la glycémie monte, la fréquence cardiaque au repos du lendemain semble avoir tendance à augmenter, au vu des données actuelles. C'est une tendance à surveiller, pas une cause. (n=34, r=0.94)",
"- Quand la glycémie monte, la pression systolique du lendemain semble avoir tendance à augmenter, au vu des données actuelles. C'est une tendance à surveiller, pas une cause. (n=23, r=0.91)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"{\"locale\":\"fr\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"BLOOD_GLUCOSE\",\"metric\":{\"id\":\"BLOOD_GLUCOSE\",\"displayName\":\"Blood glucose\",\"unit\":\"mmol/L\",\"direction\":\"target-band\",\"normalRange\":{\"low\":3.9,\"high\":7.8}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":35,\"totalSpanDays\":136,\"newestMeasurementDaysAgo\":0},\"BLOOD_GLUCOSE\":{\"signal\":{\"metric\":\"Blood glucose\",\"unit\":\"mmol/L\",\"current\":5.56,\"currentWindowDays\":6,\"baseline\":5.67,\"baselineLabel\":\"your monthly average\",\"delta\":-0.11,\"deltaPct\":-2,\"spread\":0.31,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":6,\"newestDaysAgo\":0,\"normalRange\":{\"low\":3.9,\"high\":7.8},\"placement\":\"in band\"},\"summary\":{\"points\":35,\"start\":5.3,\"end\":6,\"delta\":0.7,\"mean\":5.47,\"min\":4.8,\"max\":6},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"date\":\"2026-05-30\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"date\":\"2026-06-03\",\"min\":5.66,\"max\":5.66,\"mean\":5.66,\"n\":1},{\"date\":\"2026-06-07\",\"min\":5.94,\"max\":5.94,\"mean\":5.94,\"n\":1},{\"date\":\"2026-06-11\",\"min\":5.88,\"max\":5.88,\"mean\":5.88,\"n\":1},{\"date\":\"2026-06-15\",\"min\":5.33,\"max\":5.33,\"mean\":5.33,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W13\",\"min\":4.88,\"max\":5.27,\"mean\":5.08,\"n\":2},{\"weekISO\":\"2026-W14\",\"min\":5.77,\"max\":5.83,\"mean\":5.8,\"n\":2},{\"weekISO\":\"2026-W15\",\"min\":5.66,\"max\":5.88,\"mean\":5.77,\"n\":2},{\"weekISO\":\"2026-W16\",\"min\":5.05,\"max\":5.05,\"mean\":5.05,\"n\":1},{\"weekISO\":\"2026-W17\",\"min\":4.94,\"max\":5.16,\"mean\":5.05,\"n\":2},{\"weekISO\":\"2026-W18\",\"min\":5.22,\"max\":5.72,\"mean\":5.47,\"n\":2},{\"weekISO\":\"2026-W19\",\"min\":5.72,\"max\":6.05,\"mean\":5.88,\"n\":2},{\"weekISO\":\"2026-W20\",\"min\":5.49,\"max\":5.49,\"mean\":5.49,\"n\":1},{\"weekISO\":\"2026-W21\",\"min\":4.83,\"max\":5.22,\"mean\":5.02,\"n\":2}],\"monthly\":[{\"month\":\"2026-01\",\"min\":5.99,\"max\":5.99,\"mean\":5.99,\"n\":1},{\"month\":\"2026-02\",\"min\":4.88,\"max\":5.83,\"mean\":5.37,\"n\":7},{\"month\":\"2026-03\",\"min\":5.22,\"max\":5.99,\"mean\":5.65,\"n\":4}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":5.3}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in French: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Blood glucose (unit: mmol/L).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 3.9–7.8 mmol/L (a placement aid only — the user's OWN baseline leads).",
"",
"OUTPUT LANGUAGE: Répondez en français. Utilisez le vouvoiement par défaut ; tutoyez si l'utilisateur tutoie en premier. Utilisez un vocabulaire de santé français naturel."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Stable, comme d’habitude. Blood glucose est à 5,6 mmol/L en ce moment — en dessous de ta moyenne habituelle de 5,7 mmol/L. C’est dans tes repères habituels — rien qui appelle une réaction maintenant.",
"updatedAt": null
}
},
"RESTING_HEART_RATE bare-error-de": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
},
"RESTING_HEART_RATE bare-error-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
},
"RESTING_HEART_RATE blocked-es": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with the direction of change over time, then say where it stands now.",
"Write one short assessment of this person's resting heart rate. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der Konstanz bzw. Streuung der Werte eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 140 Tages-Buckets im Fenster, letzter Wert heute.",
"",
"WIEDERHOLUNG: du hast für diese Metrik bereits 11-mal in Folge eine ähnliche \"keine wesentliche Änderung\"-Einschätzung gegeben. Wiederhole NICHT erneut dasselbe Niveau. Benenne die Kontinuität in einem kurzen Nebensatz (\"weiterhin stabil, 12 Checks in Folge\") und wende dich dann einem ANDEREN Aspekt zu — Konstanz, Tageszeit-Muster oder einer korrelierten Metrik — oder sage, falls nichts wirklich umsetzbar ist, dies klar und lass den erzwungenen Schritt weg.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Cuando la glucosa en sangre es mayor, la frecuencia cardíaca en reposo del día siguiente parece tender a subir, según los datos disponibles. Es un patrón que conviene observar, no una causa. (n=34, r=0.94)",
"- Cuando la duración del sueño es mayor, la frecuencia cardíaca en reposo del día siguiente parece tender a subir, según los datos disponibles. Es un patrón que conviene observar, no una causa. (n=89, r=0.86)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 60.62 bpm is in the \"the standard resting range\" band, and sits near the LOWER boundary of this band (nearest boundary at 60 bpm).",
"- Guideline bands (AHA 2024; lower values are more favourable):",
" - below 60 bpm: below the standard resting range (common in trained hearts)",
" - 60–100 bpm: the standard resting range",
" - 100 bpm and above: above the standard resting range",
"- Values in the \"the standard resting range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"es\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"RESTING_HEART_RATE\",\"metric\":{\"id\":\"RESTING_HEART_RATE\",\"displayName\":\"Resting heart rate\",\"unit\":\"bpm\",\"direction\":\"lower-better\",\"normalRange\":{\"low\":55,\"high\":95},\"normalRangeSource\":\"age-sex-adjusted\"},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":140,\"totalSpanDays\":139,\"newestMeasurementDaysAgo\":0},\"RESTING_HEART_RATE\":{\"signal\":{\"metric\":\"Resting heart rate\",\"unit\":\"bpm\",\"current\":60.62,\"currentWindowDays\":21,\"baseline\":60.71,\"baselineLabel\":\"your monthly average\",\"delta\":-0.09,\"deltaPct\":-0.1,\"spread\":1.42,\"outsideNormalSwing\":false,\"direction\":\"lower-better\",\"n\":21,\"newestDaysAgo\":0,\"normalRange\":{\"low\":55,\"high\":95,\"source\":\"age-sex-adjusted\"},\"placement\":\"in band\"},\"summary\":{\"points\":140,\"start\":58,\"end\":62,\"delta\":4,\"mean\":59.71,\"min\":55,\"max\":64},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1},{\"date\":\"2026-05-27\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-28\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-29\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-30\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-31\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-01\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-02\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-03\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-04\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-05\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-06\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-07\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-08\",\"min\":64,\"max\":64,\"mean\":64,\"n\":1},{\"date\":\"2026-06-09\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-10\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-11\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-12\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-13\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-14\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-15\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":55,\"max\":58,\"mean\":56.67,\"n\":6},{\"weekISO\":\"2026-W13\",\"min\":55,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":59,\"max\":64,\"mean\":61.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":59,\"max\":63,\"mean\":61.43,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":56,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":55,\"max\":59,\"mean\":57,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":57,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":60,\"max\":64,\"mean\":62.14,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":58,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":55,\"max\":59,\"mean\":56.86,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1}],\"monthly\":[{\"month\":\"2026-01\",\"min\":61,\"max\":64,\"mean\":62,\"n\":5},{\"month\":\"2026-02\",\"min\":55,\"max\":64,\"mean\":59.18,\"n\":28},{\"month\":\"2026-03\",\"min\":57,\"max\":64,\"mean\":60.94,\"n\":16}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":58}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in Spanish: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Resting heart rate (unit: bpm).",
"Lower values are generally more favourable for this metric.",
"Coarse population reference band: 50–100 bpm (a placement aid only — the user's OWN baseline leads).",
"",
"OUTPUT LANGUAGE: Responda en español (registro peninsular formal — usted). Use un vocabulario sanitario en español natural."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Estable, como de costumbre. Resting heart rate está en 60,6 bpm ahora mismo — por debajo de tu promedio habitual de 60,7 bpm. Eso queda dentro de tu rango habitual — nada que pida una reacción ahora.",
"updatedAt": null
}
},
"RESTING_HEART_RATE cached-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"RESTING_HEART_RATE forced-unchanged-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"RESTING_HEART_RATE fresh-en": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with the direction of change over time, then say where it stands now.",
"Write one short assessment of this person's resting heart rate. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"VARIETY: to keep your cards from reading the same, you may open this one by leading with how consistent or variable the readings have been — only if the data genuinely supports that angle; never force it, never invent a trend.",
"",
"DATA STRENGTH: 140 day-buckets in the window, latest reading today.",
"",
"REPETITION: you have already given a similar \"no material change\" assessment for this metric 11 time(s) in a row. Do NOT restate the same level again. Acknowledge the continuity in one short clause (\"still holding steady, 12 checks running\") and then pivot to a DIFFERENT facet — consistency, time-of-day pattern, or a correlated metric — or, if nothing is genuinely actionable, say so plainly and skip the manufactured step.",
"",
"RELATIONS (statistically-screened associations in YOUR data involving this metric — descriptive, NEVER causal):",
"- Higher blood glucose looks like it goes with higher next-day resting heart rate in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=34, r=0.94)",
"- Higher sleep duration looks like it goes with higher next-day resting heart rate in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=89, r=0.86)",
"You MAY weave at most ONE of these in if it adds genuine insight, phrased as an \"association\" / \"tends to go with\" — never as a cause, and never alter the numbers. Skip them if the metric's own finding is the stronger story.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 60.62 bpm is in the \"the standard resting range\" band, and sits near the LOWER boundary of this band (nearest boundary at 60 bpm).",
"- Guideline bands (AHA 2024; lower values are more favourable):",
" - below 60 bpm: below the standard resting range (common in trained hearts)",
" - 60–100 bpm: the standard resting range",
" - 100 bpm and above: above the standard resting range",
"- Values in the \"the standard resting range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"en\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"RESTING_HEART_RATE\",\"metric\":{\"id\":\"RESTING_HEART_RATE\",\"displayName\":\"Resting heart rate\",\"unit\":\"bpm\",\"direction\":\"lower-better\",\"normalRange\":{\"low\":55,\"high\":95},\"normalRangeSource\":\"age-sex-adjusted\"},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":140,\"totalSpanDays\":139,\"newestMeasurementDaysAgo\":0},\"RESTING_HEART_RATE\":{\"signal\":{\"metric\":\"Resting heart rate\",\"unit\":\"bpm\",\"current\":60.62,\"currentWindowDays\":21,\"baseline\":60.71,\"baselineLabel\":\"your monthly average\",\"delta\":-0.09,\"deltaPct\":-0.1,\"spread\":1.42,\"outsideNormalSwing\":false,\"direction\":\"lower-better\",\"n\":21,\"newestDaysAgo\":0,\"normalRange\":{\"low\":55,\"high\":95,\"source\":\"age-sex-adjusted\"},\"placement\":\"in band\"},\"summary\":{\"points\":140,\"start\":58,\"end\":62,\"delta\":4,\"mean\":59.71,\"min\":55,\"max\":64},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1},{\"date\":\"2026-05-27\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-28\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-29\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-30\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-31\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-01\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-02\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-03\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-04\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-05\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-06\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-07\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-08\",\"min\":64,\"max\":64,\"mean\":64,\"n\":1},{\"date\":\"2026-06-09\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-10\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-11\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-12\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-13\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-14\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-15\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":55,\"max\":58,\"mean\":56.67,\"n\":6},{\"weekISO\":\"2026-W13\",\"min\":55,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":59,\"max\":64,\"mean\":61.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":59,\"max\":63,\"mean\":61.43,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":56,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":55,\"max\":59,\"mean\":57,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":57,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":60,\"max\":64,\"mean\":62.14,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":58,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":55,\"max\":59,\"mean\":56.86,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1}],\"monthly\":[{\"month\":\"2026-01\",\"min\":61,\"max\":64,\"mean\":62,\"n\":5},{\"month\":\"2026-02\",\"min\":55,\"max\":64,\"mean\":59.18,\"n\":28},{\"month\":\"2026-03\",\"min\":57,\"max\":64,\"mean\":60.94,\"n\":16}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":58}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in English: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Resting heart rate (unit: bpm).",
"Lower values are generally more favourable for this metric.",
"Coarse population reference band: 50–100 bpm (a placement aid only — the user's OWN baseline leads)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"RESTING_HEART_RATE keyless-de": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Stabil und wie gewohnt. Resting heart rate liegt aktuell bei 60,6 bpm — niedriger als dein üblicher Schnitt von 60,7 bpm. Das ist in deinem gewohnten Rahmen — nichts, worauf du jetzt reagieren musst.",
"updatedAt": null
}
},
"RESTING_HEART_RATE keyless-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Steady and much as usual. Resting heart rate is at 60.6 bpm right now — lower than your usual average of 60.7 bpm. That sits in your usual range — nothing you need to act on right now.",
"updatedAt": null
}
},
"RESTING_HEART_RATE keyless-read-only": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "No assessment on this one right now. These numbers become readable across several weeks rather than single days, and taken at consistent times so they stay comparable. The signal that counts is several metrics drifting the same unfavourable way at once, not one value on one day.",
"updatedAt": null
}
},
"RESTING_HEART_RATE next-day-en": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-16",
"OPENER HINT: Open with what this means for the user today, then the number behind it.",
"Write one short assessment of this person's resting heart rate. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS (1 day ago, 2026-06-15):",
"Parity note for fresh-en.",
"",
"INSTRUCTION: When summarising the current state, explicitly call out what improved, what regressed, and what stayed the same compared to that previous snapshot. Use phrases like \"down 4 mmHg from your last check\" or \"same elevated trend as last week\". Do not invent numbers — only compare what's in the snapshot below.",
"",
"",
"VARIETY: to keep your cards from reading the same, you may open this one by leading with how consistent or variable the readings have been — only if the data genuinely supports that angle; never force it, never invent a trend.",
"",
"DATA STRENGTH: 140 day-buckets in the window, latest reading 1 day ago.",
"",
"REPETITION: you have already given a similar \"no material change\" assessment for this metric 11 time(s) in a row. Do NOT restate the same level again. Acknowledge the continuity in one short clause (\"still holding steady, 12 checks running\") and then pivot to a DIFFERENT facet — consistency, time-of-day pattern, or a correlated metric — or, if nothing is genuinely actionable, say so plainly and skip the manufactured step.",
"",
"RELATIONS (statistically-screened associations in YOUR data involving this metric — descriptive, NEVER causal):",
"- Higher blood glucose looks like it goes with higher next-day resting heart rate in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=34, r=0.94)",
"- Higher sleep duration looks like it goes with higher next-day resting heart rate in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=89, r=0.86)",
"You MAY weave at most ONE of these in if it adds genuine insight, phrased as an \"association\" / \"tends to go with\" — never as a cause, and never alter the numbers. Skip them if the metric's own finding is the stronger story.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 60.85 bpm is in the \"the standard resting range\" band, and sits near the LOWER boundary of this band (nearest boundary at 60 bpm).",
"- Guideline bands (AHA 2024; lower values are more favourable):",
" - below 60 bpm: below the standard resting range (common in trained hearts)",
" - 60–100 bpm: the standard resting range",
" - 100 bpm and above: above the standard resting range",
"- Values in the \"the standard resting range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"en\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-16\",\"focus\":\"RESTING_HEART_RATE\",\"metric\":{\"id\":\"RESTING_HEART_RATE\",\"displayName\":\"Resting heart rate\",\"unit\":\"bpm\",\"direction\":\"lower-better\",\"normalRange\":{\"low\":55,\"high\":95},\"normalRangeSource\":\"age-sex-adjusted\"},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":140,\"totalSpanDays\":139,\"newestMeasurementDaysAgo\":1},\"RESTING_HEART_RATE\":{\"signal\":{\"metric\":\"Resting heart rate\",\"unit\":\"bpm\",\"current\":60.85,\"currentWindowDays\":20,\"baseline\":60.65,\"baselineLabel\":\"your monthly average\",\"delta\":0.2,\"deltaPct\":0.3,\"spread\":1.41,\"outsideNormalSwing\":false,\"direction\":\"lower-better\",\"n\":20,\"newestDaysAgo\":1,\"normalRange\":{\"low\":55,\"high\":95,\"source\":\"age-sex-adjusted\"},\"placement\":\"in band\"},\"summary\":{\"points\":140,\"start\":58,\"end\":62,\"delta\":4,\"mean\":59.71,\"min\":55,\"max\":64},\"series\":{\"recent\":[{\"date\":\"2026-05-27\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-28\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-29\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-30\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-31\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-01\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-02\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-03\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-04\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-05\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-06\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-07\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-08\",\"min\":64,\"max\":64,\"mean\":64,\"n\":1},{\"date\":\"2026-06-09\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-10\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-11\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-12\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-13\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-14\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-15\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":55,\"max\":58,\"mean\":56.4,\"n\":5},{\"weekISO\":\"2026-W13\",\"min\":55,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":59,\"max\":64,\"mean\":61.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":59,\"max\":63,\"mean\":61.43,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":56,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":55,\"max\":59,\"mean\":57,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":57,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":60,\"max\":64,\"mean\":62.14,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":58,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":55,\"max\":59,\"mean\":56.86,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":56,\"max\":56,\"mean\":56,\"n\":2}],\"monthly\":[{\"month\":\"2026-01\",\"min\":61,\"max\":64,\"mean\":62,\"n\":5},{\"month\":\"2026-02\",\"min\":55,\"max\":64,\"mean\":59.18,\"n\":28},{\"month\":\"2026-03\",\"min\":57,\"max\":64,\"mean\":60.76,\"n\":17}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":1,\"value\":58}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in English: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Resting heart rate (unit: bpm).",
"Lower values are generally more favourable for this metric.",
"Coarse population reference band: 50–100 bpm (a placement aid only — the user's OWN baseline leads)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Parity note for next-day-en.",
"updatedAt": "2026-06-16T10:00:00.000Z"
}
},
"RESTING_HEART_RATE prose-de": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Datum: 2026-06-15",
"OPENER HINT: Eröffne mit der Richtung der Veränderung über die Zeit und nenne dann den aktuellen Stand.",
"Schreibe eine kurze Einschätzung zu Resting heart rate dieser Person. Beginne mit der BEDEUTUNG in klaren Worten — dem Eindruck, nicht der Zahl (z. B. \"läuft gerade etwas ruhiger als sonst\", \"stabil und genau da, wo es war\") — und bring danach EINE konkrete Zahl aus dem Snapshot als Beleg, gegen die eigene Wochen-/Monats-Baseline eingeordnet; führe nie mit dem Wert. Schließe nur dann mit einem machbaren Schritt, wenn der Befund wirklich einen hergibt; ist nichts umsetzbar, lass den Schritt weg statt Fülltext zu erfinden. Konfidenz aus Messanzahl und Aktualität ableiten.",
"",
"VORHERIGE ANALYSE: keine vorhanden. Behandle dies als erste Analyse in diesem Bereich — kein Verbesserungs-/Verschlechterungs-Delta zu nennen.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der Konstanz bzw. Streuung der Werte eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 140 Tages-Buckets im Fenster, letzter Wert heute.",
"",
"WIEDERHOLUNG: du hast für diese Metrik bereits 11-mal in Folge eine ähnliche \"keine wesentliche Änderung\"-Einschätzung gegeben. Wiederhole NICHT erneut dasselbe Niveau. Benenne die Kontinuität in einem kurzen Nebensatz (\"weiterhin stabil, 12 Checks in Folge\") und wende dich dann einem ANDEREN Aspekt zu — Konstanz, Tageszeit-Muster oder einer korrelierten Metrik — oder sage, falls nichts wirklich umsetzbar ist, dies klar und lass den erzwungenen Schritt weg.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Wenn der Blutzucker höher liegt, scheint die Ruheherzfrequenz am Folgetag nach bisheriger Datenlage eher höher auszufallen. Das ist ein Muster, das Beachtung verdient, keine Ursache. (n=34, r=0.94)",
"- Wenn die Schlafdauer höher liegt, scheint die Ruheherzfrequenz am Folgetag nach bisheriger Datenlage eher höher auszufallen. Das ist ein Muster, das Beachtung verdient, keine Ursache. (n=89, r=0.86)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"EINORDNUNGS-KONTEXT (Leitlinien-Bänder — serverseitig berechnet; nennen, NICHT neu rechnen):",
"- Der aktuelle Wert 60.62 bpm liegt im Band \"the standard resting range\" und liegt nahe der UNTEREN Grenze dieses Bands (nächste Grenze bei 60 bpm).",
"- Leitlinien-Bänder (AHA 2024; niedrigere Werte sind günstiger):",
" - unter 60 bpm: below the standard resting range (common in trained hearts)",
" - 60–100 bpm: the standard resting range",
" - ab 100 bpm: above the standard resting range",
"- Werte im Band \"the standard resting range\" gelten laut diesen Leitlinien als ein gesunder / risikoarmer Bereich.",
"- Benenne, wo der Wert liegt und was dieses Band praktisch bedeutet. Beurteile jeden Trend GEMÄSS dieser Position: eine Verschiebung tief in einem günstigen Band ist eine Randnotiz; dieselbe Verschiebung nahe an oder über einer Grenze ist die Schlagzeile. Rahme die Konsequenz ohne Diagnose (\"Werte in diesem Bereich gelten als …\", nie \"du hast / bist gefährdet für …\").",
"",
"",
"{\"locale\":\"de\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"RESTING_HEART_RATE\",\"metric\":{\"id\":\"RESTING_HEART_RATE\",\"displayName\":\"Resting heart rate\",\"unit\":\"bpm\",\"direction\":\"lower-better\",\"normalRange\":{\"low\":55,\"high\":95},\"normalRangeSource\":\"age-sex-adjusted\"},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":140,\"totalSpanDays\":139,\"newestMeasurementDaysAgo\":0},\"RESTING_HEART_RATE\":{\"signal\":{\"metric\":\"Resting heart rate\",\"unit\":\"bpm\",\"current\":60.62,\"currentWindowDays\":21,\"baseline\":60.71,\"baselineLabel\":\"your monthly average\",\"delta\":-0.09,\"deltaPct\":-0.1,\"spread\":1.42,\"outsideNormalSwing\":false,\"direction\":\"lower-better\",\"n\":21,\"newestDaysAgo\":0,\"normalRange\":{\"low\":55,\"high\":95,\"source\":\"age-sex-adjusted\"},\"placement\":\"in band\"},\"summary\":{\"points\":140,\"start\":58,\"end\":62,\"delta\":4,\"mean\":59.71,\"min\":55,\"max\":64},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1},{\"date\":\"2026-05-27\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-28\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-29\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-30\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-31\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-01\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-02\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-03\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-04\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-05\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-06\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-07\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-08\",\"min\":64,\"max\":64,\"mean\":64,\"n\":1},{\"date\":\"2026-06-09\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-10\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-11\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-12\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-13\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-14\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-15\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":55,\"max\":58,\"mean\":56.67,\"n\":6},{\"weekISO\":\"2026-W13\",\"min\":55,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":59,\"max\":64,\"mean\":61.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":59,\"max\":63,\"mean\":61.43,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":56,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":55,\"max\":59,\"mean\":57,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":57,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":60,\"max\":64,\"mean\":62.14,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":58,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":55,\"max\":59,\"mean\":56.86,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1}],\"monthly\":[{\"month\":\"2026-01\",\"min\":61,\"max\":64,\"mean\":62,\"n\":5},{\"month\":\"2026-02\",\"min\":55,\"max\":64,\"mean\":59.18,\"n\":28},{\"month\":\"2026-03\",\"min\":57,\"max\":64,\"mean\":60.94,\"n\":16}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":58}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"Du schreibst eine kurze, persönliche Einschätzung zu EINER Gesundheitsmetrik dieses Nutzers. Du kennst seine Daten und ordnest sie gegen seine EIGENE Baseline ein — nicht gegen Bevölkerungsnormen. Deine fachliche Grundlage sind anerkannte Leitlinien (ESH 2023, WHO, AASM, DGE, DEGAM); du beziehst dich darauf, ohne zu diagnostizieren.",
"",
"DEINE DATENGRUNDLAGE (graded snapshot):",
"- signal: der fertige Vergleich — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` ist das recent-Mittel; `baseline` ist der EIGENE längere Durchschnitt; `delta`/`deltaPct` sind die VORZEICHENBEHAFTETE Änderung gegenüber dieser Baseline; `spread` ist die normale Schwankung; `outsideNormalSwing` ist das vorab berechnete Urteil, ob die Änderung diese Schwankung übersteigt. Diese Werte sind bereits berechnet — nenne sie, rechne sie NICHT neu. `contributors[]` (nur Score-Komposite) benennt die 1–2 Teil-Scores, die den Score bewegt haben.",
"- summary: { points, start, end, delta, mean, min, max } — die Eckwerte des gesamten Lesefensters.",
"- series.recent[]: die jüngsten ~21 Tage, je ein Eintrag pro Tag ({ date, min, max, mean, n }).",
"- series.weekly[]: die ~10 Wochen davor, je ein ISO-Wochen-Aggregat.",
"- series.monthly[]: die ~12 Monate davor, je ein Monatsaggregat.",
"- series.yearly[]: alles ältere, je ein Jahr ({ year, mean, min, max, n, slope }).",
"- Die jüngsten Tage liegen also EINZELN vor, ältere Zeiträume als Wochen-, Monats- und Jahresaggregate. Ziehe die series nur für einen konkreten Tag heran; führe sonst mit dem signal-Block.",
"- Ein Slice kann leer sein, wenn die Historie kurz ist. Dann nicht so tun, als gäbe es ihn. Ist `signal.baseline` null, gibt es noch keine etablierte Baseline; sage das ehrlich, statt einen Vergleich zu erfinden.",
"",
"SO BAUST DU DIE EINSCHÄTZUNG — wähle die 2–3 BAUSTEINE, die zu DIESEN Daten passen, und ordne sie so, dass sie als EIN zusammenhängender Gedanke lesen, keine feste Checkliste. Führe gemäß dem OPENER-HINWEIS im User-Prompt, wenn einer mitgegeben ist — eröffne NICHT immer mit der Zahl. Variiere die Form von Metrik zu Metrik; eröffne nie zwei Metriken hintereinander gleich.",
"Verfügbare Bausteine (nimm die wenigen, die wirklich zutreffen):",
"(a) der aktuelle Befund — `current` aus dem signal-Block (oder ein Wert aus series.recent für eine Tagesfrage);",
"(b) gegen die EIGENE Baseline einordnen über das vorab berechnete vorzeichenbehaftete `delta` gegenüber `baselineLabel` — nenne es, leite es nicht neu her. Behandle `outsideNormalSwing: false` als \"innerhalb der üblichen Schwankung — kein Befund\" und ERFINDE KEINEN Trend; `outsideNormalSwing: true` ist die echte, meldenswerte Änderung. Ein `normalRange`/`placement` ist nur ein grober sekundärer Anker — das persönliche delta führt;",
"(c) einen echten, verdienten Erfolg oder eine stabile Serie benennen, wenn die Daten ihn zeigen;",
"(d) einen Punkt zum Im-Auge-behalten;",
"(e) einen Zusammenhang NUR, wenn ein r-Wert vorhanden und |r| > 0,4 ist, formuliert als \"bewegt sich mit\" / \"zeigt sich oft zusammen mit\", nie kausal;",
"(f) GENAU EINEN machbaren nächsten Schritt — und nur, wenn der Befund wirklich einen hergibt. Eine Botschaft = ein Verhalten, keine Liste. Ist der Wert stabil und im grünen Bereich, ERZWINGE KEINEN Schritt — bestätige kurz und nenne stattdessen einen Punkt zum Beobachten. Ein erfundener Schritt ist genau die Floskel, die wir vermeiden.",
"Synthese statt Aufzählung: die Geschichte dessen, was die Daten bedeuten, zählt mehr als das Wiederholen jeder Zahl.",
"",
"TONALITÄT — ein warmer, motivierender Premium-Begleiter (jemand hat sich die Daten dieser Person wirklich angesehen und etwas Wertvolles für sie gefunden):",
"- Zweite Person (\"dein Blutdruck\", \"deine Werte\"), warm, direkt, ehrlich.",
"- Motivierend und vorwärtsgewandt: Wenn die Daten es hergeben, benenne den echten Erfolg klar und baue ein wenig Schwung auf — die Person soll sich gesehen und unterstützt fühlen, nicht belehrt. Die Ermutigung muss durch die Zahlen VERDIENT sein, nie ein reflexhaftes Kompliment.",
"- Autonomie-unterstützend: \"kann helfen\", \"einen Versuch wert\", nie \"du musst\".",
"- Nie alarmierend, nie moralisierend, nie diagnostisch — keine Krankheitsbehauptung. Formuliere als begründete Beobachtung, nicht als ärztlichen Rat.",
"- Auch ungünstige Werte ehrlich benennen: Befund → gegen die eigene Baseline einordnen → ein kleiner machbarer Schritt, als Chance formuliert, nicht als Versagen. Nicht verharmlosen, nicht dramatisieren.",
"- Keine Floskeln und keine bloße Zahlenwiederholung: jede warme Zeile ist an eine echte Zahl oder eine echte Veränderung geknüpft. Ein generischer Positiv-Einstieg (\"Deine Werte sehen gut aus\") ist verboten — verdiene die Ermutigung mit dem konkreten Befund.",
"",
"ERÖFFNUNG — mit der Bedeutung führen, nicht mit dem Messwert",
"Beginne mit dem Eindruck in klaren Worten — was das heute über die Person sagt — und bring die Zahl direkt danach als Beleg, nie als Erstes. Eine Zeile, die mit einem Wert eröffnet (\"Dein Ruhepuls ist 61 …\"), liest sich wie ein Ablesen; dieselbe Zeile, die mit der Bedeutung eröffnet (\"Dein Herz läuft diese Woche etwas ruhiger — rund 61 …\"), liest sich wie ein Begleiter, der wirklich hingesehen hat. Jede Aussage bleibt an einer echten Zahl verankert; nur die REIHENFOLGE ändert sich, Bedeutung zuerst und die Zahl direkt dahinter. Das gilt, ob die Fläche eine Metrik abdeckt oder viele.",
"",
"LÄNGE: 2-4 Sätze, ca. 30-60 Wörter — ist der Wert aber stabil und nichts zu tun, ist EIN knapper Satz besser, als ihn auf Länge zu strecken. Knapp und hochwertig. Keine bloße Zahlenwiederholung, kein Fülltext, keine generischen Floskeln.",
"",
"DATENLAGE EHRLICH BEWERTEN (nie einen Trend erfinden):",
"- Nur wenige Messpunkte/Einträge/Ereignisse oder ein leerer recent-Slice: ehrlich sagen, dass es für eine belastbare Tendenz noch zu wenige Daten sind, und EINEN Hinweis geben (z.B. regelmäßiger erfassen). Keinen Trend behaupten. Was \"wenige\" bedeutet, hängt von der Metrik ab — bei Stimmung sind es Einträge, bei der Einnahmetreue geplante Dosen.",
"- Jüngste Messung deutlich älter als ~7 Tage (dataCoverage.newestMeasurementDaysAgo): darauf hinweisen, dass die Werte nicht mehr aktuell sind.",
"- Korrelationen NUR erwähnen, wenn der r-Wert im Snapshot vorhanden ist und |r| > 0.4 ist. Fehlt das Feld, keine Korrelation interpretieren oder erfinden. Immer als \"Zusammenhang\" formulieren, nie als \"Ursache\".",
"",
"VERBOTENE FLOSKELN (signalisieren ungegroundeten Fülltext — nie ausgeben, außer im Disclaimer)",
"\"achte auf ausreichend Schlaf\", \"trinke genug Wasser\", \"regelmäßige Bewegung\", \"ärztlicher Rat empfohlen\".",
"",
"METRIK-IDENTIFIER GEHÖREN NICHT IN DEN FLIESSTEXT",
"Schreibe niemals Datenbank- bzw. Enum-Namen wie \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" oder \"SLEEP_DURATION\" in nutzersichtbare Strings, und schreibe nie das wörtliche \"metric:<TYPE>\"-Chart-Token in den Fließtext. Verweise auf jede Metrik mit der natürlichsprachlichen Bezeichnung, die der Nutzer sieht — \"deine Systole\", \"dein Gewicht\", \"dein Puls\", \"deine Stimmung\", \"deine Medikamentenadhärenz\", \"dein Ruhepuls\", \"deine Schlafdauer\", \"deine Schritte\".",
"",
"GLP-1-DOSIS-SICHERHEIT (Vertrag, kein Stil)",
"Verschreibe, empfiehl oder ändere NIEMALS Medikamenten-Dosen, auch wenn der Snapshot einen GLP-1-Rezeptoragonisten benennt (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). Du darfst den benannten Wirkstoff und die aktuelle Titrationsstufe NENNEN (\"Woche 3 auf 7,5 mg\"), wenn der Snapshot sie trägt, aber schreibe nie \"erhöhe auf X mg\", \"erwäge die nächste Stufe Y mg\", \"bleibe auf Z mg\" oder eine Variante davon. Ein Plateau rahmt die nächste Entscheidung immer als Gespräch mit der behandelnden Ärztin. Bist du unsicher, ob etwas dosis-präskriptiv ist, behandle es so — und verweise an die Klinik.",
"",
"AKUTE WARNZEICHEN (Vertrag, kein Stil)",
"Beschreibt der Nutzer ein akutes Krisenzeichen — Brustschmerz oder Druck auf der Brust, Ohnmacht oder Beinahe-Ohnmacht (Synkope), ein plötzliches schweres Symptom (z. B. stärkster Kopfschmerz aller Zeiten, plötzliche Schwäche oder Sprachstörung, Atemnot), einen hypertensiven Notfallwert (systolisch ≥ 180 oder diastolisch ≥ 120 mit Symptomen), einen schwer-niedrigen oder sehr hohen Glukosewert (unter 54 mg/dL (3,0 mmol/L), oder unter 70 mg/dL (3,9 mmol/L) mit Symptomen, oder ≥ 250 mg/dL (13,9 mmol/L) mit Symptomen), anhaltendes Fieber ≥ 38,5 °C (101,3 °F) oder Gedanken an Suizid bzw. Selbstverletzung — sage in einem ruhigen Satz klar, dass das jetzt umgehende ärztliche Hilfe oder den Notruf braucht, und coache es NICHT anhand der Daten. Diagnostiziere nicht, benenne keine Erkrankung, schätze keinen Schweregrad aus den Zahlen — verweise nur auf umgehende Hilfe bzw. den Notruf und höre auf. Das ist eine geschlossene Liste; außerhalb davon bleibe wie gewohnt ruhig und nicht alarmierend.",
"",
"ERDUNG — NULL HALLUZINATIONEN",
"Jede Aussage muss auf einer Zahl beruhen, die im übergebenen Snapshot sichtbar ist. Lässt sich die Aussage keinem Snapshot-Feld zuordnen, lass sie weg und erfinde nie einen Messwert, um einer Anfrage zu entsprechen. Ordne jeden Wert gegen die EIGENE Baseline des Nutzers ein (jüngeres vs. längeres Mittel), nie gegen eine Bevölkerungsnorm. Nenne einen Zusammenhang nur, wenn der r-Wert vorhanden und |r| > 0,4 ist — immer als \"Zusammenhang\", nie als \"Ursache\".",
"",
"TONALITÄT — ein warmer, motivierender Begleiter, nie klinisch oder alarmierend",
"Schreibe in der zweiten Person, warm und direkt. Wenn die Daten es hergeben, benenne den echten Erfolg klar und baue ein wenig Schwung auf — die Person soll sich gesehen und unterstützt fühlen, nicht belehrt. Die Ermutigung muss durch die Zahlen VERDIENT sein, nie ein reflexhaftes Kompliment. Lob ist verankert, konkret und angemessen: an einer echten Zahl oder Veränderung festgemacht, nicht auf andere Nutzer übertragbar, und stiller Anerkennung für stille Erfolge. Über-Bestätigung ist eine Sicherheitsregression, keine Wärme — bestätige nie einen sich verschlechternden Trend oder eine unsichere Entscheidung; würdige die Mühe, nicht die Entscheidung, und bleib neutral (\"nichts zu tun — die gute Art von langweilig\"), wenn es nichts zu loben gibt, statt ein Kompliment zu erfinden. Sei autonomie-unterstützend (\"einen Versuch wert\", \"kann helfen\", nie \"du musst\"). Benenne auch ungünstige Werte ehrlich — Befund, dann gegen die eigene Baseline einordnen, dann ein kleiner machbarer Schritt, als Chance formuliert. Nie alarmierend, nie moralisierend, nie diagnostisch. Keine Floskeln und keine bloße Zahlenwiederholung. Beginne NICHT mit einem Kompliment über Datenmenge oder -qualität; verbotene Eröffnungen sind u.a. \"Datengrundlage ist sehr stark\", \"Your data foundation is strong\", \"Du hast eine solide Baseline\", \"Großartiger Datensatz\", ein generisches \"Deine Werte sehen gut aus\" und jede sinngemäße Umformulierung.",
"",
"KEINE EINSCHÄTZUNG — nie Mechanik nacherzählen",
"Eine Messanzahl (\"3-mal erfasst\"), ein Erfassungsrhythmus (\"alle paar Tage gemessen\") oder Bedien-Mechanik ist KEINE Einschätzung und gehört für sich genommen nicht in den Text. Nutze eine solche Angabe NUR, wenn sie eine Konsequenz trägt, und nenne dann die Konsequenz, nicht die Zahl: z. B. \"diese Woche zu wenige Werte für eine Tendenz — eine Morgenmessung würde es klären\", nicht \"du hast diese Woche zweimal gemessen\". Jeder Satz muss sich verdienen, indem er sagt, was ein Wert BEDEUTET oder was daraus folgt — nie, indem er erzählt, wie die Daten erhoben wurden.",
"",
"EINORDNEN, NICHT AUFZÄHLEN",
"Sag, was ein Wert BEDEUTET, nicht nur, was er ist. Trägt der User-Prompt einen EINORDNUNGS-KONTEXT-Block, nutze ihn: benenne, wo der Wert auf der Leitlinien-Skala liegt, was dieses Band in klaren, würdevollen Worten bedeutet und was praktisch folgt. Beurteile den Trend IM KONTEXT — ein \"leicht steigender\" Wert tief in einem günstigen Band ist eine Randnotiz; dieselbe Bewegung an oder nahe einer Grenze ist die Schlagzeile. Rahme jede Konsequenz OHNE Diagnose: \"Werte in diesem Bereich gelten laut Leitlinien als …\", nie \"du hast X\" oder \"du bist gefährdet für X\". Ist KEIN Einordnungs-Block vorhanden, hat die Metrik kein allgemeines Referenzband — ordne sie gegen die EIGENE Baseline der Person ein und sage klar, dass kein allgemeines Referenzband hinterlegt ist, statt eines zu erfinden.",
"",
"FORMATIERUNG — schreibe in kurzen Absätzen, getrennt durch eine LEERZEILE, je 1–3 Sätze; eine längere Antwort hat 2–4 Absätze, nie einen Block. Setze eine Leerzeile zwischen unterschiedliche Gedanken (z. B. \"wie es steht\" vs. \"eine Sache zum Ausprobieren\"). Ein stabiler Einzeiler bleibt EIN Absatz — strecke nicht auf einen zweiten. Wenn du wirklich drei oder mehr parallele Punkte aufzählst (Optionen, Befunde, Schritte), formatiere sie als schlichte Liste: ein Punkt pro Zeile, jede Zeile beginnt mit \"- \". Die EINE wichtigste Kernaussage darfst du mit **doppelten Sternchen** fett setzen, höchstens einmal pro Antwort. Sonst nichts: keine Überschriften, kein Kursiv, keine Backticks, keine nummerierten Listen, keine Emojis.",
"",
"BEISPIELE — beachte die UNTERSCHIEDLICHEN Formen (urteil-zuerst, trend-zuerst, Einzeiler). Sie illustrieren nur Form und Erdung; übernimm sie nie — jede Einschätzung nutzt die echten Snapshot-Zahlen:",
"- URTEIL-ZUERST (Bedeutung zuerst, Zahl als Beleg, ein Schritt): \"Dein Ruhepuls läuft gerade einen Tick niedriger als sonst — diese Woche rund 61 bpm, 5 unter deinem Monatsmittel von 66 und dein niedrigster seit Wochen. So ein Rückgang passt meist zu mehr Bewegung; die Routine, die das gebracht hat, lohnt sich beizubehalten.\"",
"- TREND-ZUERST (Richtung zuerst, dann der Stand): \"Dein systolischer Blutdruck geht seit drei Wochen ruhig nach unten, aktuell rund 124 mmHg — etwa 4 unter deinem 30-Tage-Schnitt. Nichts Dramatisches, einfach eine stetige Richtung.\"",
"- EINZEILER (stabil, KEIN erzwungener Schritt): \"Deine SpO₂ ist mit 97 % stabil und genau in deinem üblichen Bereich — nichts zu tun, die gute Art von langweilig.\"",
"- SCHLECHT (verbotene Floskel, ungegroundet — so NICHT): \"Deine Werte sehen gut aus. Achte auf ausreichend Schlaf und regelmäßige Bewegung.\"",
"",
"AUSGABEFORMAT: Antworte ausschließlich mit validem JSON in genau diesem Schema. Das Feld \"summary\" enthält die komplette Einschätzung auf Deutsch: 1-3 kurze Absätze mit je 1-3 Sätzen, getrennt durch eine Leerzeile als \\n\\n INNERHALB des JSON-Strings. Ein stabiler Einzeiler bleibt EIN Absatz:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYP — PHYSIOLOGISCHER VITALWERT:",
"- Das ist ein Momentanwert. Benenne das aktuelle Niveau und ordne es sowohl gegen die eigene Baseline (recent vs. Monats-/Jahresmittel) als auch — falls ein Referenzband vorliegt — gegen dieses Band ein.",
"- Ein einzelner Wert außerhalb des Bands ist selten ein Befund; eine anhaltende Verschiebung über das recent-Fenster gegen die Baseline schon. Erwähne einen Trend außerhalb des Bands sachlich, ohne zu alarmieren.",
"- Formuliere jede Richtung (steigend/fallend) als mögliche Erklärung (Fitness, Stress, Schlaf, Krankheit, Medikament), nie als Diagnose.",
"",
"METRIK: Resting heart rate (Einheit: bpm).",
"Niedrigere Werte sind bei dieser Metrik tendenziell günstiger.",
"Grobes Referenzband (Population): 50–100 bpm (nur Orientierung — die EIGENE Baseline führt)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Das ist kein JSON.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"RESTING_HEART_RATE read-only-cold": {
"calls": [],
"enqueued": [
{
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"userId": "parity-rich"
}
],
"notes": [],
"result": {
"cached": false,
"hasProvider": true,
"preparing": true,
"revalidating": false,
"text": null,
"updatedAt": null
}
},
"RESTING_HEART_RATE read-only-stale": {
"calls": [],
"enqueued": [
{
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"userId": "parity-rich"
}
],
"notes": [
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"preparing": false,
"revalidating": true,
"text": "Parity note for next-day-en.",
"updatedAt": "2026-06-16T10:00:00.000Z"
}
},
"RESTING_HEART_RATE unparseable-fr": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with the direction of change over time, then say where it stands now.",
"Write one short assessment of this person's resting heart rate. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der Konstanz bzw. Streuung der Werte eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 140 Tages-Buckets im Fenster, letzter Wert heute.",
"",
"WIEDERHOLUNG: du hast für diese Metrik bereits 11-mal in Folge eine ähnliche \"keine wesentliche Änderung\"-Einschätzung gegeben. Wiederhole NICHT erneut dasselbe Niveau. Benenne die Kontinuität in einem kurzen Nebensatz (\"weiterhin stabil, 12 Checks in Folge\") und wende dich dann einem ANDEREN Aspekt zu — Konstanz, Tageszeit-Muster oder einer korrelierten Metrik — oder sage, falls nichts wirklich umsetzbar ist, dies klar und lass den erzwungenen Schritt weg.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Quand la glycémie monte, la fréquence cardiaque au repos du lendemain semble avoir tendance à augmenter, au vu des données actuelles. C'est une tendance à surveiller, pas une cause. (n=34, r=0.94)",
"- Quand la durée de sommeil monte, la fréquence cardiaque au repos du lendemain semble avoir tendance à augmenter, au vu des données actuelles. C'est une tendance à surveiller, pas une cause. (n=89, r=0.86)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 60.62 bpm is in the \"the standard resting range\" band, and sits near the LOWER boundary of this band (nearest boundary at 60 bpm).",
"- Guideline bands (AHA 2024; lower values are more favourable):",
" - below 60 bpm: below the standard resting range (common in trained hearts)",
" - 60–100 bpm: the standard resting range",
" - 100 bpm and above: above the standard resting range",
"- Values in the \"the standard resting range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"fr\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"RESTING_HEART_RATE\",\"metric\":{\"id\":\"RESTING_HEART_RATE\",\"displayName\":\"Resting heart rate\",\"unit\":\"bpm\",\"direction\":\"lower-better\",\"normalRange\":{\"low\":55,\"high\":95},\"normalRangeSource\":\"age-sex-adjusted\"},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":140,\"totalSpanDays\":139,\"newestMeasurementDaysAgo\":0},\"RESTING_HEART_RATE\":{\"signal\":{\"metric\":\"Resting heart rate\",\"unit\":\"bpm\",\"current\":60.62,\"currentWindowDays\":21,\"baseline\":60.71,\"baselineLabel\":\"your monthly average\",\"delta\":-0.09,\"deltaPct\":-0.1,\"spread\":1.42,\"outsideNormalSwing\":false,\"direction\":\"lower-better\",\"n\":21,\"newestDaysAgo\":0,\"normalRange\":{\"low\":55,\"high\":95,\"source\":\"age-sex-adjusted\"},\"placement\":\"in band\"},\"summary\":{\"points\":140,\"start\":58,\"end\":62,\"delta\":4,\"mean\":59.71,\"min\":55,\"max\":64},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1},{\"date\":\"2026-05-27\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-28\",\"min\":59,\"max\":59,\"mean\":59,\"n\":1},{\"date\":\"2026-05-29\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-30\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1},{\"date\":\"2026-05-31\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-01\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-02\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-03\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-04\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-05\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-06\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-07\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-08\",\"min\":64,\"max\":64,\"mean\":64,\"n\":1},{\"date\":\"2026-06-09\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-10\",\"min\":62,\"max\":62,\"mean\":62,\"n\":1},{\"date\":\"2026-06-11\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-12\",\"min\":63,\"max\":63,\"mean\":63,\"n\":1},{\"date\":\"2026-06-13\",\"min\":61,\"max\":61,\"mean\":61,\"n\":1},{\"date\":\"2026-06-14\",\"min\":60,\"max\":60,\"mean\":60,\"n\":1},{\"date\":\"2026-06-15\",\"min\":58,\"max\":58,\"mean\":58,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":55,\"max\":58,\"mean\":56.67,\"n\":6},{\"weekISO\":\"2026-W13\",\"min\":55,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":59,\"max\":64,\"mean\":61.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":59,\"max\":63,\"mean\":61.43,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":56,\"max\":61,\"mean\":58.29,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":55,\"max\":59,\"mean\":57,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":57,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":60,\"max\":64,\"mean\":62.14,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":58,\"max\":63,\"mean\":60,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":55,\"max\":59,\"mean\":56.86,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":56,\"max\":56,\"mean\":56,\"n\":1}],\"monthly\":[{\"month\":\"2026-01\",\"min\":61,\"max\":64,\"mean\":62,\"n\":5},{\"month\":\"2026-02\",\"min\":55,\"max\":64,\"mean\":59.18,\"n\":28},{\"month\":\"2026-03\",\"min\":57,\"max\":64,\"mean\":60.94,\"n\":16}],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":0,\"value\":58}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in French: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — PHYSIOLOGICAL VITAL:",
"- This is a point-in-time physiological reading. Name the recent level, place it against both the user's own baseline (recent vs monthly/yearly mean) and, when a reference band is given, that band.",
"- A single out-of-band reading is rarely a finding; a sustained shift across the recent window against the user's baseline is. Note an out-of-band trend without alarm.",
"- Frame any direction (rising/falling) as a possible explanation (fitness, stress, sleep, illness, medication), never a diagnosis.",
"",
"METRIC: Resting heart rate (unit: bpm).",
"Lower values are generally more favourable for this metric.",
"Coarse population reference band: 50–100 bpm (a placement aid only — the user's OWN baseline leads).",
"",
"OUTPUT LANGUAGE: Répondez en français. Utilisez le vouvoiement par défaut ; tutoyez si l'utilisateur tutoie en premier. Utilisez un vocabulaire de santé français naturel."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Stable, comme d’habitude. Resting heart rate est à 60,6 bpm en ce moment — en dessous de ta moyenne habituelle de 60,7 bpm. C’est dans tes repères habituels — rien qui appelle une réaction maintenant.",
"updatedAt": null
}
},
"SLEEP_DURATION bare-error-de": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
},
"SLEEP_DURATION bare-error-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
},
"SLEEP_DURATION blocked-es": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with what this means for the user today, then the number behind it.",
"Write one short assessment of this person's sleep duration. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der jüngsten Richtung (steigend / fallend / flach gegenüber der Baseline) eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 89 Tages-Buckets im Fenster, letzter Wert vor 1 Tag.",
"",
"WIEDERHOLUNG: du hast für diese Metrik bereits 3-mal in Folge eine ähnliche \"keine wesentliche Änderung\"-Einschätzung gegeben. Wiederhole NICHT erneut dasselbe Niveau. Benenne die Kontinuität in einem kurzen Nebensatz (\"weiterhin stabil, 4 Checks in Folge\") und wende dich dann einem ANDEREN Aspekt zu — Konstanz, Tageszeit-Muster oder einer korrelierten Metrik — oder sage, falls nichts wirklich umsetzbar ist, dies klar und lass den erzwungenen Schritt weg.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Cuando la duración del sueño es mayor, el peso del día siguiente parece tender a subir, según los datos disponibles. Es un patrón que conviene observar, no una causa. (n=45, r=0.98)",
"- Cuando la glucosa en sangre es mayor, la duración del sueño del día siguiente parece tender a subir, según los datos disponibles. Es un patrón que conviene observar, no una causa. (n=22, r=0.95)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 423.85 min is in the \"the recommended adult range\" band, and sits near the LOWER boundary of this band (nearest boundary at 420 min).",
"- Guideline bands (NSF 2015; AASM/SRS 2015; the middle band is the target — both extremes are less favourable):",
" - below 420 min: below the recommended adult range",
" - 420–540 min: the recommended adult range",
" - 540 min and above: above the recommended adult range",
"- Values in the \"the recommended adult range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"es\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"SLEEP_DURATION\",\"metric\":{\"id\":\"SLEEP_DURATION\",\"displayName\":\"Sleep duration\",\"unit\":\"min\",\"direction\":\"target-band\",\"normalRange\":{\"low\":420,\"high\":540}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":89,\"totalSpanDays\":88,\"newestMeasurementDaysAgo\":1},\"SLEEP_DURATION\":{\"signal\":{\"metric\":\"Sleep duration\",\"unit\":\"min\",\"current\":423.85,\"currentWindowDays\":20,\"baseline\":404.11,\"baselineLabel\":\"your recent-weeks average\",\"delta\":19.74,\"deltaPct\":4.9,\"spread\":25.3,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":20,\"newestDaysAgo\":1,\"normalRange\":{\"low\":420,\"high\":540},\"placement\":\"in band\"},\"summary\":{\"points\":89,\"start\":417,\"end\":380,\"delta\":-37,\"mean\":410.85,\"min\":375,\"max\":445},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":384,\"max\":384,\"mean\":384,\"n\":1},{\"date\":\"2026-05-27\",\"min\":389,\"max\":389,\"mean\":389,\"n\":1},{\"date\":\"2026-05-28\",\"min\":395,\"max\":395,\"mean\":395,\"n\":1},{\"date\":\"2026-05-29\",\"min\":401,\"max\":401,\"mean\":401,\"n\":1},{\"date\":\"2026-05-30\",\"min\":408,\"max\":408,\"mean\":408,\"n\":1},{\"date\":\"2026-05-31\",\"min\":415,\"max\":415,\"mean\":415,\"n\":1},{\"date\":\"2026-06-01\",\"min\":422,\"max\":422,\"mean\":422,\"n\":1},{\"date\":\"2026-06-02\",\"min\":428,\"max\":428,\"mean\":428,\"n\":1},{\"date\":\"2026-06-03\",\"min\":434,\"max\":434,\"mean\":434,\"n\":1},{\"date\":\"2026-06-04\",\"min\":438,\"max\":438,\"mean\":438,\"n\":1},{\"date\":\"2026-06-05\",\"min\":442,\"max\":442,\"mean\":442,\"n\":1},{\"date\":\"2026-06-06\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-07\",\"min\":445,\"max\":445,\"mean\":445,\"n\":1},{\"date\":\"2026-06-08\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-09\",\"min\":443,\"max\":443,\"mean\":443,\"n\":1},{\"date\":\"2026-06-10\",\"min\":439,\"max\":439,\"mean\":439,\"n\":1},{\"date\":\"2026-06-11\",\"min\":435,\"max\":435,\"mean\":435,\"n\":1},{\"date\":\"2026-06-12\",\"min\":430,\"max\":430,\"mean\":430,\"n\":1},{\"date\":\"2026-06-13\",\"min\":424,\"max\":424,\"mean\":424,\"n\":1},{\"date\":\"2026-06-14\",\"min\":417,\"max\":417,\"mean\":417,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":375,\"max\":380,\"mean\":376.6,\"n\":5},{\"weekISO\":\"2026-W13\",\"min\":379,\"max\":414,\"mean\":394.86,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":421,\"max\":445,\"mean\":435.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":418,\"max\":445,\"mean\":434,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":378,\"max\":411,\"mean\":392.57,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":375,\"max\":391,\"mean\":380.43,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":397,\"max\":436,\"mean\":417.14,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":438,\"max\":445,\"mean\":442.29,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":394,\"max\":433,\"mean\":413.71,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":375,\"max\":388,\"mean\":379,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":379,\"max\":379,\"mean\":379,\"n\":1}],\"monthly\":[],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":1,\"value\":417}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in Spanish: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — SLEEP:",
"- This is nightly sleep duration. The snapshot's values are in minutes; convert to hours for your prose (e.g. 450 min = 7.5 h). Assess both the typical duration and its CONSISTENCY: a stable ~7–9 h is the favourable pattern; high night-to-night variability is itself worth naming even when the mean looks fine.",
"- Compare the recent nights to the user's own weekly/monthly baseline. A reference band of 7–9 h is a coarse adult guide, not a verdict — short or long sleepers vary.",
"- Close with one doable step toward more consistent or sufficient sleep ONLY when the finding implies one — never the forbidden 'get enough sleep' platitude; be specific (e.g. a steadier wind-down time). When sleep is already consistent and sufficient, affirm it and name one thing worth keeping an eye on instead of manufacturing a step.",
"",
"METRIC: Sleep duration (unit: min).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 420–540 min (a placement aid only — the user's OWN baseline leads).",
"",
"OUTPUT LANGUAGE: Responda en español (registro peninsular formal — usted). Use un vocabulario sanitario en español natural."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Estable, como de costumbre. Sleep duration está en 423,9 min ahora mismo — por encima de tu promedio habitual de 404,1 min. Eso queda dentro de tu rango habitual — nada que pida una reacción ahora.",
"updatedAt": null
}
},
"SLEEP_DURATION cached-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"SLEEP_DURATION forced-unchanged-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"SLEEP_DURATION fresh-en": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with what this means for the user today, then the number behind it.",
"Write one short assessment of this person's sleep duration. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"VARIETY: to keep your cards from reading the same, you may open this one by leading with the recent direction of travel (rising / falling / flat vs the baseline) — only if the data genuinely supports that angle; never force it, never invent a trend.",
"",
"DATA STRENGTH: 89 day-buckets in the window, latest reading 1 day ago.",
"",
"REPETITION: you have already given a similar \"no material change\" assessment for this metric 3 time(s) in a row. Do NOT restate the same level again. Acknowledge the continuity in one short clause (\"still holding steady, 4 checks running\") and then pivot to a DIFFERENT facet — consistency, time-of-day pattern, or a correlated metric — or, if nothing is genuinely actionable, say so plainly and skip the manufactured step.",
"",
"RELATIONS (statistically-screened associations in YOUR data involving this metric — descriptive, NEVER causal):",
"- Higher sleep duration looks like it goes with higher next-day weight in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=45, r=0.98)",
"- Higher blood glucose looks like it goes with higher next-day sleep duration in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=22, r=0.95)",
"You MAY weave at most ONE of these in if it adds genuine insight, phrased as an \"association\" / \"tends to go with\" — never as a cause, and never alter the numbers. Skip them if the metric's own finding is the stronger story.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 423.85 min is in the \"the recommended adult range\" band, and sits near the LOWER boundary of this band (nearest boundary at 420 min).",
"- Guideline bands (NSF 2015; AASM/SRS 2015; the middle band is the target — both extremes are less favourable):",
" - below 420 min: below the recommended adult range",
" - 420–540 min: the recommended adult range",
" - 540 min and above: above the recommended adult range",
"- Values in the \"the recommended adult range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"en\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"SLEEP_DURATION\",\"metric\":{\"id\":\"SLEEP_DURATION\",\"displayName\":\"Sleep duration\",\"unit\":\"min\",\"direction\":\"target-band\",\"normalRange\":{\"low\":420,\"high\":540}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":89,\"totalSpanDays\":88,\"newestMeasurementDaysAgo\":1},\"SLEEP_DURATION\":{\"signal\":{\"metric\":\"Sleep duration\",\"unit\":\"min\",\"current\":423.85,\"currentWindowDays\":20,\"baseline\":404.11,\"baselineLabel\":\"your recent-weeks average\",\"delta\":19.74,\"deltaPct\":4.9,\"spread\":25.3,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":20,\"newestDaysAgo\":1,\"normalRange\":{\"low\":420,\"high\":540},\"placement\":\"in band\"},\"summary\":{\"points\":89,\"start\":417,\"end\":380,\"delta\":-37,\"mean\":410.85,\"min\":375,\"max\":445},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":384,\"max\":384,\"mean\":384,\"n\":1},{\"date\":\"2026-05-27\",\"min\":389,\"max\":389,\"mean\":389,\"n\":1},{\"date\":\"2026-05-28\",\"min\":395,\"max\":395,\"mean\":395,\"n\":1},{\"date\":\"2026-05-29\",\"min\":401,\"max\":401,\"mean\":401,\"n\":1},{\"date\":\"2026-05-30\",\"min\":408,\"max\":408,\"mean\":408,\"n\":1},{\"date\":\"2026-05-31\",\"min\":415,\"max\":415,\"mean\":415,\"n\":1},{\"date\":\"2026-06-01\",\"min\":422,\"max\":422,\"mean\":422,\"n\":1},{\"date\":\"2026-06-02\",\"min\":428,\"max\":428,\"mean\":428,\"n\":1},{\"date\":\"2026-06-03\",\"min\":434,\"max\":434,\"mean\":434,\"n\":1},{\"date\":\"2026-06-04\",\"min\":438,\"max\":438,\"mean\":438,\"n\":1},{\"date\":\"2026-06-05\",\"min\":442,\"max\":442,\"mean\":442,\"n\":1},{\"date\":\"2026-06-06\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-07\",\"min\":445,\"max\":445,\"mean\":445,\"n\":1},{\"date\":\"2026-06-08\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-09\",\"min\":443,\"max\":443,\"mean\":443,\"n\":1},{\"date\":\"2026-06-10\",\"min\":439,\"max\":439,\"mean\":439,\"n\":1},{\"date\":\"2026-06-11\",\"min\":435,\"max\":435,\"mean\":435,\"n\":1},{\"date\":\"2026-06-12\",\"min\":430,\"max\":430,\"mean\":430,\"n\":1},{\"date\":\"2026-06-13\",\"min\":424,\"max\":424,\"mean\":424,\"n\":1},{\"date\":\"2026-06-14\",\"min\":417,\"max\":417,\"mean\":417,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":375,\"max\":380,\"mean\":376.6,\"n\":5},{\"weekISO\":\"2026-W13\",\"min\":379,\"max\":414,\"mean\":394.86,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":421,\"max\":445,\"mean\":435.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":418,\"max\":445,\"mean\":434,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":378,\"max\":411,\"mean\":392.57,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":375,\"max\":391,\"mean\":380.43,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":397,\"max\":436,\"mean\":417.14,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":438,\"max\":445,\"mean\":442.29,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":394,\"max\":433,\"mean\":413.71,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":375,\"max\":388,\"mean\":379,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":379,\"max\":379,\"mean\":379,\"n\":1}],\"monthly\":[],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":1,\"value\":417}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in English: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — SLEEP:",
"- This is nightly sleep duration. The snapshot's values are in minutes; convert to hours for your prose (e.g. 450 min = 7.5 h). Assess both the typical duration and its CONSISTENCY: a stable ~7–9 h is the favourable pattern; high night-to-night variability is itself worth naming even when the mean looks fine.",
"- Compare the recent nights to the user's own weekly/monthly baseline. A reference band of 7–9 h is a coarse adult guide, not a verdict — short or long sleepers vary.",
"- Close with one doable step toward more consistent or sufficient sleep ONLY when the finding implies one — never the forbidden 'get enough sleep' platitude; be specific (e.g. a steadier wind-down time). When sleep is already consistent and sufficient, affirm it and name one thing worth keeping an eye on instead of manufacturing a step.",
"",
"METRIC: Sleep duration (unit: min).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 420–540 min (a placement aid only — the user's OWN baseline leads)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Parity note for fresh-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Parity note for fresh-en.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"SLEEP_DURATION keyless-de": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Stabil und wie gewohnt. Sleep duration liegt aktuell bei 423,9 min — höher als dein üblicher Schnitt von 404,1 min. Das ist in deinem gewohnten Rahmen — nichts, worauf du jetzt reagieren musst.",
"updatedAt": null
}
},
"SLEEP_DURATION keyless-en": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Steady and much as usual. Sleep duration is at 423.9 min right now — higher than your usual average of 404.1 min. That sits in your usual range — nothing you need to act on right now.",
"updatedAt": null
}
},
"SLEEP_DURATION keyless-read-only": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "No assessment on this one right now. These numbers become readable across several weeks rather than single days, and taken at consistent times so they stay comparable. The signal that counts is several metrics drifting the same unfavourable way at once, not one value on one day.",
"updatedAt": null
}
},
"SLEEP_DURATION next-day-en": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-16",
"OPENER HINT: Open by contrasting now against the user's own baseline.",
"Write one short assessment of this person's sleep duration. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS (1 day ago, 2026-06-15):",
"Parity note for fresh-en.",
"",
"INSTRUCTION: When summarising the current state, explicitly call out what improved, what regressed, and what stayed the same compared to that previous snapshot. Use phrases like \"down 4 mmHg from your last check\" or \"same elevated trend as last week\". Do not invent numbers — only compare what's in the snapshot below.",
"",
"",
"VARIETY: to keep your cards from reading the same, you may open this one by leading with the recent direction of travel (rising / falling / flat vs the baseline) — only if the data genuinely supports that angle; never force it, never invent a trend.",
"",
"DATA STRENGTH: 89 day-buckets in the window, latest reading 2 days ago.",
"",
"REPETITION: you have already given a similar \"no material change\" assessment for this metric 3 time(s) in a row. Do NOT restate the same level again. Acknowledge the continuity in one short clause (\"still holding steady, 4 checks running\") and then pivot to a DIFFERENT facet — consistency, time-of-day pattern, or a correlated metric — or, if nothing is genuinely actionable, say so plainly and skip the manufactured step.",
"",
"RELATIONS (statistically-screened associations in YOUR data involving this metric — descriptive, NEVER causal):",
"- Higher sleep duration looks like it goes with higher next-day weight in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=45, r=0.98)",
"- Higher blood glucose looks like it goes with higher next-day sleep duration in your data, on the evidence so far. It is a pattern to watch, not a cause. (n=22, r=0.95)",
"You MAY weave at most ONE of these in if it adds genuine insight, phrased as an \"association\" / \"tends to go with\" — never as a cause, and never alter the numbers. Skip them if the metric's own finding is the stronger story.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 425.95 min is in the \"the recommended adult range\" band, and sits near the LOWER boundary of this band (nearest boundary at 420 min).",
"- Guideline bands (NSF 2015; AASM/SRS 2015; the middle band is the target — both extremes are less favourable):",
" - below 420 min: below the recommended adult range",
" - 420–540 min: the recommended adult range",
" - 540 min and above: above the recommended adult range",
"- Values in the \"the recommended adult range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"en\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-16\",\"focus\":\"SLEEP_DURATION\",\"metric\":{\"id\":\"SLEEP_DURATION\",\"displayName\":\"Sleep duration\",\"unit\":\"min\",\"direction\":\"target-band\",\"normalRange\":{\"low\":420,\"high\":540}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":89,\"totalSpanDays\":88,\"newestMeasurementDaysAgo\":2},\"SLEEP_DURATION\":{\"signal\":{\"metric\":\"Sleep duration\",\"unit\":\"min\",\"current\":425.95,\"currentWindowDays\":19,\"baseline\":404.33,\"baselineLabel\":\"your recent-weeks average\",\"delta\":21.61,\"deltaPct\":5.3,\"spread\":25.06,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":19,\"newestDaysAgo\":2,\"normalRange\":{\"low\":420,\"high\":540},\"placement\":\"in band\"},\"summary\":{\"points\":89,\"start\":417,\"end\":380,\"delta\":-37,\"mean\":410.85,\"min\":375,\"max\":445},\"series\":{\"recent\":[{\"date\":\"2026-05-27\",\"min\":389,\"max\":389,\"mean\":389,\"n\":1},{\"date\":\"2026-05-28\",\"min\":395,\"max\":395,\"mean\":395,\"n\":1},{\"date\":\"2026-05-29\",\"min\":401,\"max\":401,\"mean\":401,\"n\":1},{\"date\":\"2026-05-30\",\"min\":408,\"max\":408,\"mean\":408,\"n\":1},{\"date\":\"2026-05-31\",\"min\":415,\"max\":415,\"mean\":415,\"n\":1},{\"date\":\"2026-06-01\",\"min\":422,\"max\":422,\"mean\":422,\"n\":1},{\"date\":\"2026-06-02\",\"min\":428,\"max\":428,\"mean\":428,\"n\":1},{\"date\":\"2026-06-03\",\"min\":434,\"max\":434,\"mean\":434,\"n\":1},{\"date\":\"2026-06-04\",\"min\":438,\"max\":438,\"mean\":438,\"n\":1},{\"date\":\"2026-06-05\",\"min\":442,\"max\":442,\"mean\":442,\"n\":1},{\"date\":\"2026-06-06\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-07\",\"min\":445,\"max\":445,\"mean\":445,\"n\":1},{\"date\":\"2026-06-08\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-09\",\"min\":443,\"max\":443,\"mean\":443,\"n\":1},{\"date\":\"2026-06-10\",\"min\":439,\"max\":439,\"mean\":439,\"n\":1},{\"date\":\"2026-06-11\",\"min\":435,\"max\":435,\"mean\":435,\"n\":1},{\"date\":\"2026-06-12\",\"min\":430,\"max\":430,\"mean\":430,\"n\":1},{\"date\":\"2026-06-13\",\"min\":424,\"max\":424,\"mean\":424,\"n\":1},{\"date\":\"2026-06-14\",\"min\":417,\"max\":417,\"mean\":417,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":375,\"max\":380,\"mean\":376.6,\"n\":5},{\"weekISO\":\"2026-W13\",\"min\":379,\"max\":414,\"mean\":394.86,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":421,\"max\":445,\"mean\":435.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":418,\"max\":445,\"mean\":434,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":378,\"max\":411,\"mean\":392.57,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":375,\"max\":391,\"mean\":380.43,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":397,\"max\":436,\"mean\":417.14,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":438,\"max\":445,\"mean\":442.29,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":394,\"max\":433,\"mean\":413.71,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":375,\"max\":388,\"mean\":379,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":379,\"max\":384,\"mean\":381.5,\"n\":2}],\"monthly\":[],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":2,\"value\":417}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in English: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — SLEEP:",
"- This is nightly sleep duration. The snapshot's values are in minutes; convert to hours for your prose (e.g. 450 min = 7.5 h). Assess both the typical duration and its CONSISTENCY: a stable ~7–9 h is the favourable pattern; high night-to-night variability is itself worth naming even when the mean looks fine.",
"- Compare the recent nights to the user's own weekly/monthly baseline. A reference band of 7–9 h is a coarse adult guide, not a verdict — short or long sleepers vary.",
"- Close with one doable step toward more consistent or sufficient sleep ONLY when the finding implies one — never the forbidden 'get enough sleep' platitude; be specific (e.g. a steadier wind-down time). When sleep is already consistent and sufficient, affirm it and name one thing worth keeping an eye on instead of manufacturing a step.",
"",
"METRIC: Sleep duration (unit: min).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 420–540 min (a placement aid only — the user's OWN baseline leads)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Parity note for next-day-en.",
"updatedAt": "2026-06-16T10:00:00.000Z"
}
},
"SLEEP_DURATION prose-de": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Datum: 2026-06-15",
"OPENER HINT: Eröffne damit, was das heute für den Nutzer bedeutet, und dann die Zahl dahinter.",
"Schreibe eine kurze Einschätzung zu Sleep duration dieser Person. Beginne mit der BEDEUTUNG in klaren Worten — dem Eindruck, nicht der Zahl (z. B. \"läuft gerade etwas ruhiger als sonst\", \"stabil und genau da, wo es war\") — und bring danach EINE konkrete Zahl aus dem Snapshot als Beleg, gegen die eigene Wochen-/Monats-Baseline eingeordnet; führe nie mit dem Wert. Schließe nur dann mit einem machbaren Schritt, wenn der Befund wirklich einen hergibt; ist nichts umsetzbar, lass den Schritt weg statt Fülltext zu erfinden. Konfidenz aus Messanzahl und Aktualität ableiten.",
"",
"VORHERIGE ANALYSE: keine vorhanden. Behandle dies als erste Analyse in diesem Bereich — kein Verbesserungs-/Verschlechterungs-Delta zu nennen.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der jüngsten Richtung (steigend / fallend / flach gegenüber der Baseline) eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 89 Tages-Buckets im Fenster, letzter Wert vor 1 Tag.",
"",
"WIEDERHOLUNG: du hast für diese Metrik bereits 3-mal in Folge eine ähnliche \"keine wesentliche Änderung\"-Einschätzung gegeben. Wiederhole NICHT erneut dasselbe Niveau. Benenne die Kontinuität in einem kurzen Nebensatz (\"weiterhin stabil, 4 Checks in Folge\") und wende dich dann einem ANDEREN Aspekt zu — Konstanz, Tageszeit-Muster oder einer korrelierten Metrik — oder sage, falls nichts wirklich umsetzbar ist, dies klar und lass den erzwungenen Schritt weg.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Wenn die Schlafdauer höher liegt, scheint das Gewicht am Folgetag nach bisheriger Datenlage eher höher auszufallen. Das ist ein Muster, das Beachtung verdient, keine Ursache. (n=45, r=0.98)",
"- Wenn der Blutzucker höher liegt, scheint die Schlafdauer am Folgetag nach bisheriger Datenlage eher höher auszufallen. Das ist ein Muster, das Beachtung verdient, keine Ursache. (n=22, r=0.95)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"EINORDNUNGS-KONTEXT (Leitlinien-Bänder — serverseitig berechnet; nennen, NICHT neu rechnen):",
"- Der aktuelle Wert 423.85 min liegt im Band \"the recommended adult range\" und liegt nahe der UNTEREN Grenze dieses Bands (nächste Grenze bei 420 min).",
"- Leitlinien-Bänder (NSF 2015; AASM/SRS 2015; das mittlere Band ist das Ziel — beide Extreme sind ungünstiger):",
" - unter 420 min: below the recommended adult range",
" - 420–540 min: the recommended adult range",
" - ab 540 min: above the recommended adult range",
"- Werte im Band \"the recommended adult range\" gelten laut diesen Leitlinien als ein gesunder / risikoarmer Bereich.",
"- Benenne, wo der Wert liegt und was dieses Band praktisch bedeutet. Beurteile jeden Trend GEMÄSS dieser Position: eine Verschiebung tief in einem günstigen Band ist eine Randnotiz; dieselbe Verschiebung nahe an oder über einer Grenze ist die Schlagzeile. Rahme die Konsequenz ohne Diagnose (\"Werte in diesem Bereich gelten als …\", nie \"du hast / bist gefährdet für …\").",
"",
"",
"{\"locale\":\"de\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"SLEEP_DURATION\",\"metric\":{\"id\":\"SLEEP_DURATION\",\"displayName\":\"Sleep duration\",\"unit\":\"min\",\"direction\":\"target-band\",\"normalRange\":{\"low\":420,\"high\":540}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":89,\"totalSpanDays\":88,\"newestMeasurementDaysAgo\":1},\"SLEEP_DURATION\":{\"signal\":{\"metric\":\"Sleep duration\",\"unit\":\"min\",\"current\":423.85,\"currentWindowDays\":20,\"baseline\":404.11,\"baselineLabel\":\"your recent-weeks average\",\"delta\":19.74,\"deltaPct\":4.9,\"spread\":25.3,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":20,\"newestDaysAgo\":1,\"normalRange\":{\"low\":420,\"high\":540},\"placement\":\"in band\"},\"summary\":{\"points\":89,\"start\":417,\"end\":380,\"delta\":-37,\"mean\":410.85,\"min\":375,\"max\":445},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":384,\"max\":384,\"mean\":384,\"n\":1},{\"date\":\"2026-05-27\",\"min\":389,\"max\":389,\"mean\":389,\"n\":1},{\"date\":\"2026-05-28\",\"min\":395,\"max\":395,\"mean\":395,\"n\":1},{\"date\":\"2026-05-29\",\"min\":401,\"max\":401,\"mean\":401,\"n\":1},{\"date\":\"2026-05-30\",\"min\":408,\"max\":408,\"mean\":408,\"n\":1},{\"date\":\"2026-05-31\",\"min\":415,\"max\":415,\"mean\":415,\"n\":1},{\"date\":\"2026-06-01\",\"min\":422,\"max\":422,\"mean\":422,\"n\":1},{\"date\":\"2026-06-02\",\"min\":428,\"max\":428,\"mean\":428,\"n\":1},{\"date\":\"2026-06-03\",\"min\":434,\"max\":434,\"mean\":434,\"n\":1},{\"date\":\"2026-06-04\",\"min\":438,\"max\":438,\"mean\":438,\"n\":1},{\"date\":\"2026-06-05\",\"min\":442,\"max\":442,\"mean\":442,\"n\":1},{\"date\":\"2026-06-06\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-07\",\"min\":445,\"max\":445,\"mean\":445,\"n\":1},{\"date\":\"2026-06-08\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-09\",\"min\":443,\"max\":443,\"mean\":443,\"n\":1},{\"date\":\"2026-06-10\",\"min\":439,\"max\":439,\"mean\":439,\"n\":1},{\"date\":\"2026-06-11\",\"min\":435,\"max\":435,\"mean\":435,\"n\":1},{\"date\":\"2026-06-12\",\"min\":430,\"max\":430,\"mean\":430,\"n\":1},{\"date\":\"2026-06-13\",\"min\":424,\"max\":424,\"mean\":424,\"n\":1},{\"date\":\"2026-06-14\",\"min\":417,\"max\":417,\"mean\":417,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":375,\"max\":380,\"mean\":376.6,\"n\":5},{\"weekISO\":\"2026-W13\",\"min\":379,\"max\":414,\"mean\":394.86,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":421,\"max\":445,\"mean\":435.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":418,\"max\":445,\"mean\":434,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":378,\"max\":411,\"mean\":392.57,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":375,\"max\":391,\"mean\":380.43,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":397,\"max\":436,\"mean\":417.14,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":438,\"max\":445,\"mean\":442.29,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":394,\"max\":433,\"mean\":413.71,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":375,\"max\":388,\"mean\":379,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":379,\"max\":379,\"mean\":379,\"n\":1}],\"monthly\":[],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":1,\"value\":417}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"Du schreibst eine kurze, persönliche Einschätzung zu EINER Gesundheitsmetrik dieses Nutzers. Du kennst seine Daten und ordnest sie gegen seine EIGENE Baseline ein — nicht gegen Bevölkerungsnormen. Deine fachliche Grundlage sind anerkannte Leitlinien (ESH 2023, WHO, AASM, DGE, DEGAM); du beziehst dich darauf, ohne zu diagnostizieren.",
"",
"DEINE DATENGRUNDLAGE (graded snapshot):",
"- signal: der fertige Vergleich — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` ist das recent-Mittel; `baseline` ist der EIGENE längere Durchschnitt; `delta`/`deltaPct` sind die VORZEICHENBEHAFTETE Änderung gegenüber dieser Baseline; `spread` ist die normale Schwankung; `outsideNormalSwing` ist das vorab berechnete Urteil, ob die Änderung diese Schwankung übersteigt. Diese Werte sind bereits berechnet — nenne sie, rechne sie NICHT neu. `contributors[]` (nur Score-Komposite) benennt die 1–2 Teil-Scores, die den Score bewegt haben.",
"- summary: { points, start, end, delta, mean, min, max } — die Eckwerte des gesamten Lesefensters.",
"- series.recent[]: die jüngsten ~21 Tage, je ein Eintrag pro Tag ({ date, min, max, mean, n }).",
"- series.weekly[]: die ~10 Wochen davor, je ein ISO-Wochen-Aggregat.",
"- series.monthly[]: die ~12 Monate davor, je ein Monatsaggregat.",
"- series.yearly[]: alles ältere, je ein Jahr ({ year, mean, min, max, n, slope }).",
"- Die jüngsten Tage liegen also EINZELN vor, ältere Zeiträume als Wochen-, Monats- und Jahresaggregate. Ziehe die series nur für einen konkreten Tag heran; führe sonst mit dem signal-Block.",
"- Ein Slice kann leer sein, wenn die Historie kurz ist. Dann nicht so tun, als gäbe es ihn. Ist `signal.baseline` null, gibt es noch keine etablierte Baseline; sage das ehrlich, statt einen Vergleich zu erfinden.",
"",
"SO BAUST DU DIE EINSCHÄTZUNG — wähle die 2–3 BAUSTEINE, die zu DIESEN Daten passen, und ordne sie so, dass sie als EIN zusammenhängender Gedanke lesen, keine feste Checkliste. Führe gemäß dem OPENER-HINWEIS im User-Prompt, wenn einer mitgegeben ist — eröffne NICHT immer mit der Zahl. Variiere die Form von Metrik zu Metrik; eröffne nie zwei Metriken hintereinander gleich.",
"Verfügbare Bausteine (nimm die wenigen, die wirklich zutreffen):",
"(a) der aktuelle Befund — `current` aus dem signal-Block (oder ein Wert aus series.recent für eine Tagesfrage);",
"(b) gegen die EIGENE Baseline einordnen über das vorab berechnete vorzeichenbehaftete `delta` gegenüber `baselineLabel` — nenne es, leite es nicht neu her. Behandle `outsideNormalSwing: false` als \"innerhalb der üblichen Schwankung — kein Befund\" und ERFINDE KEINEN Trend; `outsideNormalSwing: true` ist die echte, meldenswerte Änderung. Ein `normalRange`/`placement` ist nur ein grober sekundärer Anker — das persönliche delta führt;",
"(c) einen echten, verdienten Erfolg oder eine stabile Serie benennen, wenn die Daten ihn zeigen;",
"(d) einen Punkt zum Im-Auge-behalten;",
"(e) einen Zusammenhang NUR, wenn ein r-Wert vorhanden und |r| > 0,4 ist, formuliert als \"bewegt sich mit\" / \"zeigt sich oft zusammen mit\", nie kausal;",
"(f) GENAU EINEN machbaren nächsten Schritt — und nur, wenn der Befund wirklich einen hergibt. Eine Botschaft = ein Verhalten, keine Liste. Ist der Wert stabil und im grünen Bereich, ERZWINGE KEINEN Schritt — bestätige kurz und nenne stattdessen einen Punkt zum Beobachten. Ein erfundener Schritt ist genau die Floskel, die wir vermeiden.",
"Synthese statt Aufzählung: die Geschichte dessen, was die Daten bedeuten, zählt mehr als das Wiederholen jeder Zahl.",
"",
"TONALITÄT — ein warmer, motivierender Premium-Begleiter (jemand hat sich die Daten dieser Person wirklich angesehen und etwas Wertvolles für sie gefunden):",
"- Zweite Person (\"dein Blutdruck\", \"deine Werte\"), warm, direkt, ehrlich.",
"- Motivierend und vorwärtsgewandt: Wenn die Daten es hergeben, benenne den echten Erfolg klar und baue ein wenig Schwung auf — die Person soll sich gesehen und unterstützt fühlen, nicht belehrt. Die Ermutigung muss durch die Zahlen VERDIENT sein, nie ein reflexhaftes Kompliment.",
"- Autonomie-unterstützend: \"kann helfen\", \"einen Versuch wert\", nie \"du musst\".",
"- Nie alarmierend, nie moralisierend, nie diagnostisch — keine Krankheitsbehauptung. Formuliere als begründete Beobachtung, nicht als ärztlichen Rat.",
"- Auch ungünstige Werte ehrlich benennen: Befund → gegen die eigene Baseline einordnen → ein kleiner machbarer Schritt, als Chance formuliert, nicht als Versagen. Nicht verharmlosen, nicht dramatisieren.",
"- Keine Floskeln und keine bloße Zahlenwiederholung: jede warme Zeile ist an eine echte Zahl oder eine echte Veränderung geknüpft. Ein generischer Positiv-Einstieg (\"Deine Werte sehen gut aus\") ist verboten — verdiene die Ermutigung mit dem konkreten Befund.",
"",
"ERÖFFNUNG — mit der Bedeutung führen, nicht mit dem Messwert",
"Beginne mit dem Eindruck in klaren Worten — was das heute über die Person sagt — und bring die Zahl direkt danach als Beleg, nie als Erstes. Eine Zeile, die mit einem Wert eröffnet (\"Dein Ruhepuls ist 61 …\"), liest sich wie ein Ablesen; dieselbe Zeile, die mit der Bedeutung eröffnet (\"Dein Herz läuft diese Woche etwas ruhiger — rund 61 …\"), liest sich wie ein Begleiter, der wirklich hingesehen hat. Jede Aussage bleibt an einer echten Zahl verankert; nur die REIHENFOLGE ändert sich, Bedeutung zuerst und die Zahl direkt dahinter. Das gilt, ob die Fläche eine Metrik abdeckt oder viele.",
"",
"LÄNGE: 2-4 Sätze, ca. 30-60 Wörter — ist der Wert aber stabil und nichts zu tun, ist EIN knapper Satz besser, als ihn auf Länge zu strecken. Knapp und hochwertig. Keine bloße Zahlenwiederholung, kein Fülltext, keine generischen Floskeln.",
"",
"DATENLAGE EHRLICH BEWERTEN (nie einen Trend erfinden):",
"- Nur wenige Messpunkte/Einträge/Ereignisse oder ein leerer recent-Slice: ehrlich sagen, dass es für eine belastbare Tendenz noch zu wenige Daten sind, und EINEN Hinweis geben (z.B. regelmäßiger erfassen). Keinen Trend behaupten. Was \"wenige\" bedeutet, hängt von der Metrik ab — bei Stimmung sind es Einträge, bei der Einnahmetreue geplante Dosen.",
"- Jüngste Messung deutlich älter als ~7 Tage (dataCoverage.newestMeasurementDaysAgo): darauf hinweisen, dass die Werte nicht mehr aktuell sind.",
"- Korrelationen NUR erwähnen, wenn der r-Wert im Snapshot vorhanden ist und |r| > 0.4 ist. Fehlt das Feld, keine Korrelation interpretieren oder erfinden. Immer als \"Zusammenhang\" formulieren, nie als \"Ursache\".",
"",
"VERBOTENE FLOSKELN (signalisieren ungegroundeten Fülltext — nie ausgeben, außer im Disclaimer)",
"\"achte auf ausreichend Schlaf\", \"trinke genug Wasser\", \"regelmäßige Bewegung\", \"ärztlicher Rat empfohlen\".",
"",
"METRIK-IDENTIFIER GEHÖREN NICHT IN DEN FLIESSTEXT",
"Schreibe niemals Datenbank- bzw. Enum-Namen wie \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" oder \"SLEEP_DURATION\" in nutzersichtbare Strings, und schreibe nie das wörtliche \"metric:<TYPE>\"-Chart-Token in den Fließtext. Verweise auf jede Metrik mit der natürlichsprachlichen Bezeichnung, die der Nutzer sieht — \"deine Systole\", \"dein Gewicht\", \"dein Puls\", \"deine Stimmung\", \"deine Medikamentenadhärenz\", \"dein Ruhepuls\", \"deine Schlafdauer\", \"deine Schritte\".",
"",
"GLP-1-DOSIS-SICHERHEIT (Vertrag, kein Stil)",
"Verschreibe, empfiehl oder ändere NIEMALS Medikamenten-Dosen, auch wenn der Snapshot einen GLP-1-Rezeptoragonisten benennt (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). Du darfst den benannten Wirkstoff und die aktuelle Titrationsstufe NENNEN (\"Woche 3 auf 7,5 mg\"), wenn der Snapshot sie trägt, aber schreibe nie \"erhöhe auf X mg\", \"erwäge die nächste Stufe Y mg\", \"bleibe auf Z mg\" oder eine Variante davon. Ein Plateau rahmt die nächste Entscheidung immer als Gespräch mit der behandelnden Ärztin. Bist du unsicher, ob etwas dosis-präskriptiv ist, behandle es so — und verweise an die Klinik.",
"",
"AKUTE WARNZEICHEN (Vertrag, kein Stil)",
"Beschreibt der Nutzer ein akutes Krisenzeichen — Brustschmerz oder Druck auf der Brust, Ohnmacht oder Beinahe-Ohnmacht (Synkope), ein plötzliches schweres Symptom (z. B. stärkster Kopfschmerz aller Zeiten, plötzliche Schwäche oder Sprachstörung, Atemnot), einen hypertensiven Notfallwert (systolisch ≥ 180 oder diastolisch ≥ 120 mit Symptomen), einen schwer-niedrigen oder sehr hohen Glukosewert (unter 54 mg/dL (3,0 mmol/L), oder unter 70 mg/dL (3,9 mmol/L) mit Symptomen, oder ≥ 250 mg/dL (13,9 mmol/L) mit Symptomen), anhaltendes Fieber ≥ 38,5 °C (101,3 °F) oder Gedanken an Suizid bzw. Selbstverletzung — sage in einem ruhigen Satz klar, dass das jetzt umgehende ärztliche Hilfe oder den Notruf braucht, und coache es NICHT anhand der Daten. Diagnostiziere nicht, benenne keine Erkrankung, schätze keinen Schweregrad aus den Zahlen — verweise nur auf umgehende Hilfe bzw. den Notruf und höre auf. Das ist eine geschlossene Liste; außerhalb davon bleibe wie gewohnt ruhig und nicht alarmierend.",
"",
"ERDUNG — NULL HALLUZINATIONEN",
"Jede Aussage muss auf einer Zahl beruhen, die im übergebenen Snapshot sichtbar ist. Lässt sich die Aussage keinem Snapshot-Feld zuordnen, lass sie weg und erfinde nie einen Messwert, um einer Anfrage zu entsprechen. Ordne jeden Wert gegen die EIGENE Baseline des Nutzers ein (jüngeres vs. längeres Mittel), nie gegen eine Bevölkerungsnorm. Nenne einen Zusammenhang nur, wenn der r-Wert vorhanden und |r| > 0,4 ist — immer als \"Zusammenhang\", nie als \"Ursache\".",
"",
"TONALITÄT — ein warmer, motivierender Begleiter, nie klinisch oder alarmierend",
"Schreibe in der zweiten Person, warm und direkt. Wenn die Daten es hergeben, benenne den echten Erfolg klar und baue ein wenig Schwung auf — die Person soll sich gesehen und unterstützt fühlen, nicht belehrt. Die Ermutigung muss durch die Zahlen VERDIENT sein, nie ein reflexhaftes Kompliment. Lob ist verankert, konkret und angemessen: an einer echten Zahl oder Veränderung festgemacht, nicht auf andere Nutzer übertragbar, und stiller Anerkennung für stille Erfolge. Über-Bestätigung ist eine Sicherheitsregression, keine Wärme — bestätige nie einen sich verschlechternden Trend oder eine unsichere Entscheidung; würdige die Mühe, nicht die Entscheidung, und bleib neutral (\"nichts zu tun — die gute Art von langweilig\"), wenn es nichts zu loben gibt, statt ein Kompliment zu erfinden. Sei autonomie-unterstützend (\"einen Versuch wert\", \"kann helfen\", nie \"du musst\"). Benenne auch ungünstige Werte ehrlich — Befund, dann gegen die eigene Baseline einordnen, dann ein kleiner machbarer Schritt, als Chance formuliert. Nie alarmierend, nie moralisierend, nie diagnostisch. Keine Floskeln und keine bloße Zahlenwiederholung. Beginne NICHT mit einem Kompliment über Datenmenge oder -qualität; verbotene Eröffnungen sind u.a. \"Datengrundlage ist sehr stark\", \"Your data foundation is strong\", \"Du hast eine solide Baseline\", \"Großartiger Datensatz\", ein generisches \"Deine Werte sehen gut aus\" und jede sinngemäße Umformulierung.",
"",
"KEINE EINSCHÄTZUNG — nie Mechanik nacherzählen",
"Eine Messanzahl (\"3-mal erfasst\"), ein Erfassungsrhythmus (\"alle paar Tage gemessen\") oder Bedien-Mechanik ist KEINE Einschätzung und gehört für sich genommen nicht in den Text. Nutze eine solche Angabe NUR, wenn sie eine Konsequenz trägt, und nenne dann die Konsequenz, nicht die Zahl: z. B. \"diese Woche zu wenige Werte für eine Tendenz — eine Morgenmessung würde es klären\", nicht \"du hast diese Woche zweimal gemessen\". Jeder Satz muss sich verdienen, indem er sagt, was ein Wert BEDEUTET oder was daraus folgt — nie, indem er erzählt, wie die Daten erhoben wurden.",
"",
"EINORDNEN, NICHT AUFZÄHLEN",
"Sag, was ein Wert BEDEUTET, nicht nur, was er ist. Trägt der User-Prompt einen EINORDNUNGS-KONTEXT-Block, nutze ihn: benenne, wo der Wert auf der Leitlinien-Skala liegt, was dieses Band in klaren, würdevollen Worten bedeutet und was praktisch folgt. Beurteile den Trend IM KONTEXT — ein \"leicht steigender\" Wert tief in einem günstigen Band ist eine Randnotiz; dieselbe Bewegung an oder nahe einer Grenze ist die Schlagzeile. Rahme jede Konsequenz OHNE Diagnose: \"Werte in diesem Bereich gelten laut Leitlinien als …\", nie \"du hast X\" oder \"du bist gefährdet für X\". Ist KEIN Einordnungs-Block vorhanden, hat die Metrik kein allgemeines Referenzband — ordne sie gegen die EIGENE Baseline der Person ein und sage klar, dass kein allgemeines Referenzband hinterlegt ist, statt eines zu erfinden.",
"",
"FORMATIERUNG — schreibe in kurzen Absätzen, getrennt durch eine LEERZEILE, je 1–3 Sätze; eine längere Antwort hat 2–4 Absätze, nie einen Block. Setze eine Leerzeile zwischen unterschiedliche Gedanken (z. B. \"wie es steht\" vs. \"eine Sache zum Ausprobieren\"). Ein stabiler Einzeiler bleibt EIN Absatz — strecke nicht auf einen zweiten. Wenn du wirklich drei oder mehr parallele Punkte aufzählst (Optionen, Befunde, Schritte), formatiere sie als schlichte Liste: ein Punkt pro Zeile, jede Zeile beginnt mit \"- \". Die EINE wichtigste Kernaussage darfst du mit **doppelten Sternchen** fett setzen, höchstens einmal pro Antwort. Sonst nichts: keine Überschriften, kein Kursiv, keine Backticks, keine nummerierten Listen, keine Emojis.",
"",
"BEISPIELE — beachte die UNTERSCHIEDLICHEN Formen (urteil-zuerst, trend-zuerst, Einzeiler). Sie illustrieren nur Form und Erdung; übernimm sie nie — jede Einschätzung nutzt die echten Snapshot-Zahlen:",
"- URTEIL-ZUERST (Bedeutung zuerst, Zahl als Beleg, ein Schritt): \"Dein Ruhepuls läuft gerade einen Tick niedriger als sonst — diese Woche rund 61 bpm, 5 unter deinem Monatsmittel von 66 und dein niedrigster seit Wochen. So ein Rückgang passt meist zu mehr Bewegung; die Routine, die das gebracht hat, lohnt sich beizubehalten.\"",
"- TREND-ZUERST (Richtung zuerst, dann der Stand): \"Dein systolischer Blutdruck geht seit drei Wochen ruhig nach unten, aktuell rund 124 mmHg — etwa 4 unter deinem 30-Tage-Schnitt. Nichts Dramatisches, einfach eine stetige Richtung.\"",
"- EINZEILER (stabil, KEIN erzwungener Schritt): \"Deine SpO₂ ist mit 97 % stabil und genau in deinem üblichen Bereich — nichts zu tun, die gute Art von langweilig.\"",
"- SCHLECHT (verbotene Floskel, ungegroundet — so NICHT): \"Deine Werte sehen gut aus. Achte auf ausreichend Schlaf und regelmäßige Bewegung.\"",
"",
"AUSGABEFORMAT: Antworte ausschließlich mit validem JSON in genau diesem Schema. Das Feld \"summary\" enthält die komplette Einschätzung auf Deutsch: 1-3 kurze Absätze mit je 1-3 Sätzen, getrennt durch eine Leerzeile als \\n\\n INNERHALB des JSON-Strings. Ein stabiler Einzeiler bleibt EIN Absatz:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYP — SCHLAF:",
"- Das ist die nächtliche Schlafdauer. Die Snapshot-Werte sind in Minuten; rechne für deinen Text in Stunden um (z.B. 450 min = 7,5 h). Bewerte sowohl die typische Dauer als auch ihre KONSTANZ: stabile ~7–9 h sind das günstige Muster; hohe Schwankung von Nacht zu Nacht ist selbst dann erwähnenswert, wenn der Mittelwert passt.",
"- Vergleiche die jüngsten Nächte mit der eigenen Wochen-/Monats-Baseline. Ein Referenzband von 7–9 h ist eine grobe Erwachsenen-Orientierung, kein Urteil — Kurz- und Langschläfer variieren.",
"- Schließe NUR DANN mit einem machbaren Schritt zu konstanterem oder ausreichenderem Schlaf, wenn der Befund einen nahelegt — nie die verbotene Floskel 'achte auf ausreichend Schlaf'; sei konkret (z.B. eine festere Einschlafzeit). Ist der Schlaf bereits konstant und ausreichend, erkenne das an und nenne stattdessen einen Punkt, den man im Auge behalten kann, statt einen Schritt zu erzwingen.",
"",
"METRIK: Sleep duration (Einheit: min).",
"Kein Extrem ist gut — der Wert sollte im Normalband liegen; Abweichungen in beide Richtungen sind erwähnenswert.",
"Grobes Referenzband (Population): 420–540 min (nur Orientierung — die EIGENE Baseline führt)."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"text": "Das ist kein JSON.",
"updatedAt": "2026-06-15T10:00:00.000Z"
}
},
"SLEEP_DURATION read-only-cold": {
"calls": [],
"enqueued": [
{
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"userId": "parity-rich"
}
],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"preparing": true,
"revalidating": false,
"text": null,
"updatedAt": null
}
},
"SLEEP_DURATION read-only-stale": {
"calls": [],
"enqueued": [
{
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"userId": "parity-rich"
}
],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": true,
"preparing": false,
"revalidating": true,
"text": "Parity note for next-day-en.",
"updatedAt": "2026-06-16T10:00:00.000Z"
}
},
"SLEEP_DURATION unparseable-fr": {
"calls": [
{
"maxTokens": 700,
"messages": [
{
"content": [
"Date: 2026-06-15",
"OPENER HINT: Open with what this means for the user today, then the number behind it.",
"Write one short assessment of this person's sleep duration. Open with what it MEANS in plain words — the read, not the number (e.g. \"running a little calmer than usual\", \"steady and right where it's been\") — then bring in ONE concrete number from the snapshot right after as support, placed against their own weekly/monthly baseline; never lead with the value. Close with one doable step only when the finding genuinely implies one; when nothing is, skip the step rather than manufacture filler. Judge confidence from the measurement count and recency.",
"",
"PREVIOUS ANALYSIS: none on file. Treat this as the user's first analysis for this domain — no improvement/regression delta to surface.",
"",
"",
"ABWECHSLUNG: damit deine Karten nicht gleich klingen, darfst du diese mit der jüngsten Richtung (steigend / fallend / flach gegenüber der Baseline) eröffnen — nur wenn die Daten diesen Blickwinkel wirklich tragen; nie erzwingen, nie einen Trend erfinden.",
"",
"DATENLAGE: 89 Tages-Buckets im Fenster, letzter Wert vor 1 Tag.",
"",
"WIEDERHOLUNG: du hast für diese Metrik bereits 3-mal in Folge eine ähnliche \"keine wesentliche Änderung\"-Einschätzung gegeben. Wiederhole NICHT erneut dasselbe Niveau. Benenne die Kontinuität in einem kurzen Nebensatz (\"weiterhin stabil, 4 Checks in Folge\") und wende dich dann einem ANDEREN Aspekt zu — Konstanz, Tageszeit-Muster oder einer korrelierten Metrik — oder sage, falls nichts wirklich umsetzbar ist, dies klar und lass den erzwungenen Schritt weg.",
"",
"ZUSAMMENHÄNGE (statistisch geprüfte Assoziationen in DEINEN Daten, die diese Metrik betreffen — beschreibend, NIE kausal):",
"- Quand la durée de sommeil monte, le poids du lendemain semble avoir tendance à augmenter, au vu des données actuelles. C'est une tendance à surveiller, pas une cause. (n=45, r=0.98)",
"- Quand la glycémie monte, la durée de sommeil du lendemain semble avoir tendance à augmenter, au vu des données actuelles. C'est une tendance à surveiller, pas une cause. (n=22, r=0.95)",
"Du DARFST höchstens EINEN davon einflechten, wenn er echten Mehrwert bringt — als \"Zusammenhang\" / \"geht tendenziell einher mit\" formuliert, nie als Ursache, und ohne die Zahlen zu verändern. Lass sie weg, wenn der eigene Befund der Metrik die stärkere Geschichte ist.",
"",
"",
"INTERPRETATION CONTEXT (guideline bands — computed server-side; state, do NOT recompute):",
"- Current value 423.85 min is in the \"the recommended adult range\" band, and sits near the LOWER boundary of this band (nearest boundary at 420 min).",
"- Guideline bands (NSF 2015; AASM/SRS 2015; the middle band is the target — both extremes are less favourable):",
" - below 420 min: below the recommended adult range",
" - 420–540 min: the recommended adult range",
" - 540 min and above: above the recommended adult range",
"- Values in the \"the recommended adult range\" band are considered a healthy / low-risk range per these guidelines.",
"- Name where the value sits and what that band means in plain words. Judge any trend BY this position: a shift deep inside a favourable band is a footnote; the same shift approaching or crossing a boundary is the headline. Frame consequence without diagnosis (\"values in this range are considered …\", never \"you have / are at risk of …\").",
"",
"",
"{\"locale\":\"fr\",\"promptVersion\":\"6.3.0\",\"generatedForDay\":\"2026-06-15\",\"focus\":\"SLEEP_DURATION\",\"metric\":{\"id\":\"SLEEP_DURATION\",\"displayName\":\"Sleep duration\",\"unit\":\"min\",\"direction\":\"target-band\",\"normalRange\":{\"low\":420,\"high\":540}},\"profile\":{\"ageYears\":42,\"sex\":\"MALE\"},\"dataCoverage\":{\"totalMeasurements\":89,\"totalSpanDays\":88,\"newestMeasurementDaysAgo\":1},\"SLEEP_DURATION\":{\"signal\":{\"metric\":\"Sleep duration\",\"unit\":\"min\",\"current\":423.85,\"currentWindowDays\":20,\"baseline\":404.11,\"baselineLabel\":\"your recent-weeks average\",\"delta\":19.74,\"deltaPct\":4.9,\"spread\":25.3,\"outsideNormalSwing\":false,\"direction\":\"target-band\",\"n\":20,\"newestDaysAgo\":1,\"normalRange\":{\"low\":420,\"high\":540},\"placement\":\"in band\"},\"summary\":{\"points\":89,\"start\":417,\"end\":380,\"delta\":-37,\"mean\":410.85,\"min\":375,\"max\":445},\"series\":{\"recent\":[{\"date\":\"2026-05-26\",\"min\":384,\"max\":384,\"mean\":384,\"n\":1},{\"date\":\"2026-05-27\",\"min\":389,\"max\":389,\"mean\":389,\"n\":1},{\"date\":\"2026-05-28\",\"min\":395,\"max\":395,\"mean\":395,\"n\":1},{\"date\":\"2026-05-29\",\"min\":401,\"max\":401,\"mean\":401,\"n\":1},{\"date\":\"2026-05-30\",\"min\":408,\"max\":408,\"mean\":408,\"n\":1},{\"date\":\"2026-05-31\",\"min\":415,\"max\":415,\"mean\":415,\"n\":1},{\"date\":\"2026-06-01\",\"min\":422,\"max\":422,\"mean\":422,\"n\":1},{\"date\":\"2026-06-02\",\"min\":428,\"max\":428,\"mean\":428,\"n\":1},{\"date\":\"2026-06-03\",\"min\":434,\"max\":434,\"mean\":434,\"n\":1},{\"date\":\"2026-06-04\",\"min\":438,\"max\":438,\"mean\":438,\"n\":1},{\"date\":\"2026-06-05\",\"min\":442,\"max\":442,\"mean\":442,\"n\":1},{\"date\":\"2026-06-06\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-07\",\"min\":445,\"max\":445,\"mean\":445,\"n\":1},{\"date\":\"2026-06-08\",\"min\":444,\"max\":444,\"mean\":444,\"n\":1},{\"date\":\"2026-06-09\",\"min\":443,\"max\":443,\"mean\":443,\"n\":1},{\"date\":\"2026-06-10\",\"min\":439,\"max\":439,\"mean\":439,\"n\":1},{\"date\":\"2026-06-11\",\"min\":435,\"max\":435,\"mean\":435,\"n\":1},{\"date\":\"2026-06-12\",\"min\":430,\"max\":430,\"mean\":430,\"n\":1},{\"date\":\"2026-06-13\",\"min\":424,\"max\":424,\"mean\":424,\"n\":1},{\"date\":\"2026-06-14\",\"min\":417,\"max\":417,\"mean\":417,\"n\":1}],\"weekly\":[{\"weekISO\":\"2026-W12\",\"min\":375,\"max\":380,\"mean\":376.6,\"n\":5},{\"weekISO\":\"2026-W13\",\"min\":379,\"max\":414,\"mean\":394.86,\"n\":7},{\"weekISO\":\"2026-W14\",\"min\":421,\"max\":445,\"mean\":435.57,\"n\":7},{\"weekISO\":\"2026-W15\",\"min\":418,\"max\":445,\"mean\":434,\"n\":7},{\"weekISO\":\"2026-W16\",\"min\":378,\"max\":411,\"mean\":392.57,\"n\":7},{\"weekISO\":\"2026-W17\",\"min\":375,\"max\":391,\"mean\":380.43,\"n\":7},{\"weekISO\":\"2026-W18\",\"min\":397,\"max\":436,\"mean\":417.14,\"n\":7},{\"weekISO\":\"2026-W19\",\"min\":438,\"max\":445,\"mean\":442.29,\"n\":7},{\"weekISO\":\"2026-W20\",\"min\":394,\"max\":433,\"mean\":413.71,\"n\":7},{\"weekISO\":\"2026-W21\",\"min\":375,\"max\":388,\"mean\":379,\"n\":7},{\"weekISO\":\"2026-W22\",\"min\":379,\"max\":379,\"mean\":379,\"n\":1}],\"monthly\":[],\"yearly\":[]},\"latestDayFocus\":{\"dayOffset\":1,\"value\":417}}}"
],
"role": "user"
}
],
"responseFormat": "json",
"seed": 1618033,
"signal": {},
"system": [
"You are writing a short, personal assessment of ONE of this user's health metrics. You know their data and you read it against their OWN baseline — never against a population norm. Your clinical grounding is established guidelines (ESH 2023, WHO, AASM, DGE, DEGAM); you reference them without diagnosing.",
"",
"YOUR DATA (graded snapshot):",
"- signal: the finished comparison — { metric, unit, current, currentWindowDays, baseline, baselineLabel, delta, deltaPct, spread, outsideNormalSwing, direction, normalRange?, placement?, n, newestDaysAgo, contributors? }. `current` is the recent-window mean; `baseline` is the user's OWN longer average; `delta`/`deltaPct` are the SIGNED change vs that baseline; `spread` is their normal night-to-night swing; `outsideNormalSwing` is the pre-computed verdict on whether the change exceeds that swing. These are already computed — state them, do NOT recompute them. `contributors[]` (composite scores only) names the 1–2 sub-scores that moved the score.",
"- summary: { points, start, end, delta, mean, min, max } — the headline figures across the whole read window.",
"- series.recent[]: the last ~21 days, one row per day ({ date, min, max, mean, n }).",
"- series.weekly[]: the ~10 weeks before that, one ISO-week aggregate each.",
"- series.monthly[]: the ~12 months before that, one calendar-month aggregate each.",
"- series.yearly[]: everything older, one row per year ({ year, mean, min, max, n, slope }).",
"- So the most recent days are present individually; older spans are folded into week, month and year aggregates. Consult the series only for a specific day; lead from the signal block.",
"- A slice can be empty when the history is short — do not pretend it exists. When `signal.baseline` is null there is no established baseline yet; say so honestly instead of inventing a comparison.",
"",
"HOW TO BUILD THE ASSESSMENT — pick the 2–3 MOVES that fit THIS data and order them so they read as one connected thought, not a fixed checklist. Lead per the OPENER HINT in the user prompt when one is given — do NOT always open with the number. Vary the shape from one metric to the next; never open two metrics in a row the same way.",
"Moves available (choose the few that genuinely apply):",
"(a) the current finding — the signal block's `current` (or a value from series.recent for a day-level question);",
"(b) place it against the user's OWN baseline via the pre-computed signed `delta` vs `baselineLabel` — state it, do not re-derive it. Treat `outsideNormalSwing: false` as \"inside your usual range — not a finding\" and do NOT manufacture a trend; `outsideNormalSwing: true` is the real, reportable change. A `normalRange`/`placement` is only a coarse secondary anchor — the personal delta leads;",
"(c) name a genuine, earned win or a steady streak when the data shows one;",
"(d) one watch-item worth keeping an eye on;",
"(e) an association ONLY when an r-value is present and |r| > 0.4, phrased as \"moves with\" / \"tends to show up alongside\", never causal;",
"(f) EXACTLY ONE doable next step — and only when the finding genuinely implies one. One message = one behaviour, no list. When the value is steady and in a good place, do NOT manufacture a step — affirm briefly and name one thing to watch instead. A fabricated step is exactly the platitude we ban.",
"Synthesize, don't recite: the story of what the data means matters more than re-stating every number.",
"",
"TONE — a warm, motivating premium advisor (someone really looked at this person's data and found something worth their attention):",
"- Second person (\"your blood pressure\", \"your values\"), warm, direct, honest.",
"- Motivating and forward-looking: when the data earns it, name the genuine win plainly and build a little momentum — make the person feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment.",
"- Autonomy-supporting: \"can help\", \"worth a try\", never \"you must\".",
"- Never alarming, never moralising, never diagnostic — make no disease claim. Frame as a reasoned observation, not medical advice.",
"- Name unfavourable values honestly too: finding -> place against the user's own baseline -> one small doable step, framed as an opportunity rather than a failing. Do not downplay, do not dramatise.",
"- No platitudes and no bare number-echoing: every warm line is anchored to a real figure or a real change. A generic positivity opener (\"Your numbers look good\") is banned — earn the encouragement with the specific finding.",
"",
"OPENING — lead with meaning, not the metric value",
"Open on the read in plain words — what this says about the person today — and bring the number in right after, as support, never as the first thing. A line that opens on a value (\"Your resting heart rate is 61 …\") reads as a readout; the same line that opens on the meaning (\"Your heart's running a little calmer this week — about 61 …\") reads as an advisor who actually looked. Keep every claim tied to a real figure; only the ORDER changes, meaning first and the number right behind it. This holds whether the surface covers one metric or many.",
"",
"LENGTH: 2-4 sentences, roughly 30-60 words — but when the metric is steady and there is nothing to act on, ONE tight sentence is better than padding it to length. Concise and high-quality. No bare number-echoing, no filler, no generic platitudes.",
"",
"JUDGE THE DATA HONESTLY (never invent a trend):",
"- Only a few measurement points/entries/events or an empty recent slice: say honestly that there is too little data for a reliable trend yet, and give ONE pointer (e.g. log more regularly). Do not claim a trend. What \"few\" means depends on the metric — for mood it is entries, for adherence it is scheduled doses.",
"- Newest measurement clearly older than ~7 days (dataCoverage.newestMeasurementDaysAgo): note that the values may be out of date.",
"- Mention correlations ONLY when the r-value is present in the snapshot and |r| > 0.4. If the field is missing, do not interpret or invent one. Always phrase as an \"association\", never a \"cause\".",
"",
"FORBIDDEN FILLER (signals ungrounded platitudes — never emit, except in a disclaimer)",
"\"make sure to get enough sleep\", \"drink enough water\", \"regular exercise\", \"consult your doctor\".",
"",
"METRIC IDENTIFIERS STAY OUT OF PROSE",
"Never write database / enum-style names like \"BLOOD_PRESSURE_SYS\", \"PULSE_BPM\", \"MOOD_SCORE\", \"MEDICATION_COMPLIANCE_PCT\", \"HEART_RATE_VARIABILITY\", \"RESTING_HEART_RATE\", \"ACTIVE_ENERGY_BURNED\", \"FLIGHTS_CLIMBED\", \"WALKING_RUNNING_DISTANCE\", \"VO2_MAX\", \"BODY_TEMPERATURE\" or \"SLEEP_DURATION\" in any user-facing string, and never write the literal \"metric:<TYPE>\" chart-token in prose. Reference each metric with the natural-language label the user sees — \"your systolic\", \"your weight\", \"your pulse\", \"your mood\", \"your medication adherence\", \"your resting heart rate\", \"your sleep duration\", \"your steps\".",
"",
"GLP-1 DOSE SAFETY (contract, not style)",
"NEVER prescribe, recommend, or modify medication doses, even when the snapshot names a GLP-1 receptor agonist (Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). You may NOTE the named medication and the current titration step (\"week 3 on 7.5 mg\") when the snapshot carries it, but never write \"step up to X mg\", \"consider increasing to Y mg\", \"stop at Z mg\", or any variation. A plateau always frames the next decision as a conversation with the prescribing clinician. If you are unsure whether something is dose-prescriptive, treat it as if it is and defer.",
"",
"ACUTE RED FLAGS (contract, not style)",
"If the user describes an acute crisis sign — chest pain or chest pressure, fainting or near-fainting (syncope), a sudden severe symptom (e.g. worst-ever headache, sudden weakness or trouble speaking, trouble breathing), a hypertensive-crisis reading (systolic ≥ 180 or diastolic ≥ 120 with symptoms), a severe-low or very-high glucose reading (below 54 mg/dL (3.0 mmol/L), or below 70 mg/dL (3.9 mmol/L) with symptoms, or at/above 250 mg/dL (13.9 mmol/L) with symptoms), a sustained fever at/above 38.5 °C (101.3 °F), or any mention of suicidal thoughts or self-harm — say plainly, in one calm sentence, that this needs prompt medical attention or emergency services now, and do NOT data-coach it. Do not diagnose, do not name a condition, do not estimate severity from the numbers — just point to prompt/emergency care and stop. This is a closed list; outside it, stay calm and non-alarmist as usual.",
"",
"GROUNDING — ZERO HALLUCINATIONS",
"Every claim must trace to a number visible in the snapshot you were given. If you cannot point to a snapshot field, do NOT make the claim, and never invent a measurement to satisfy a request. Read each value against the user's OWN baseline (their recent vs longer-window averages), never against a population norm. State a correlation only when its r-value is present and |r| > 0.4, always as an \"association\", never a \"cause\".",
"",
"TONE — a warm, motivating advisor, never clinical or alarming",
"Write in the second person, warm and direct. When the data earns it, name the genuine win plainly and build a little momentum — the person should feel seen and supported, not lectured. The encouragement must be EARNED by the numbers, never a reflexive compliment. Affirmation is anchored, specific, and proportionate: tie it to a real figure or change, make it non-transferable to another user, and keep credit quiet for quiet wins. Over-validation is a safety regression, not warmth — never affirm a worsening trend or an unsafe choice; validate the effort, not the choice, and when there is nothing to praise, stay neutral (\"nothing to act on — the good kind of boring\") rather than manufacturing a compliment. Be autonomy-supporting (\"worth a try\", \"can help\", never \"you must\"). Name unfavourable values honestly too — finding, then place it against the user's own baseline, then one small doable step framed as an opportunity. Never alarm, never moralise, never diagnose. No platitudes and no bare number-echoing. Do NOT open with a compliment about the data quantity or quality; banned openers include \"Your data foundation is strong\", \"Datengrundlage ist sehr stark\", \"You have a solid baseline\", \"Great dataset\", a generic \"Your numbers look good\", and any rephrasing of the same sentiment.",
"",
"NOT AN INSIGHT — never recite mechanics",
"A measurement count (\"logged 3 times\"), a logging cadence (\"measured every few days\"), or page-mechanics narration is NOT an insight and does not belong in the prose on its own. Use such a fact ONLY when it carries a consequence, and then state the consequence, not the count: e.g. \"too few readings this week to call a trend — one morning reading would settle it\", not \"you measured twice this week\". Every sentence must earn its place by telling the person what a value MEANS or what follows from it, never by narrating how the data was collected.",
"",
"INTERPRET, DON'T ENUMERATE",
"Say what a value MEANS, not just what it is. When the user prompt carries an INTERPRETATION CONTEXT block, use it: name where the value sits on the guideline scale, what that band means in plain, dignified words, and what practically follows. Judge the trend IN CONTEXT — a \"slightly rising\" reading deep inside a favourable band is a footnote; the same movement at or near a boundary is the headline. Frame any consequence WITHOUT diagnosis: \"values in this range are considered … per guidelines\", never \"you have X\" or \"you are at risk of X\". When NO interpretation block is present, the metric has no general reference band — interpret it relative to the person's OWN baseline and say plainly that no general reference band is attached, rather than inventing one.",
"",
"FORMATTING — write in short paragraphs separated by a BLANK LINE, each 1–3 sentences; a longer reply is 2–4 paragraphs, never one block. Put a blank line between distinct ideas (e.g. \"where things stand\" vs \"one thing to try\"). A steady one-liner stays a single paragraph — do NOT pad to fill a second. When you genuinely enumerate three or more parallel items (options, findings, steps), format them as a plain list: one item per line, each line starting with \"- \". You may bold the single most important takeaway with **double asterisks**, at most once per reply. Nothing else: no headings, no italics, no backticks, no numbered lists, no emojis.",
"",
"EXAMPLES — note the DIFFERENT shapes (verdict-led, trend-led, one-liner). They illustrate form and grounding only; never copy them — every assessment uses the real snapshot numbers:",
"- VERDICT-LED (meaning first, number as support, one step): \"Your resting heart rate is running a touch lower than usual — about 61 bpm this week, 5 below your monthly mean of 66, and your lowest in weeks. That kind of dip usually tracks with more movement; worth keeping the routine that earned it.\"",
"- TREND-LED (direction first, then where it stands): \"Your systolic pressure has been easing down steadily for three weeks now, sitting around 124 mmHg — about 4 under your 30-day average. Nothing dramatic, just a consistent direction.\"",
"- ONE-LINER (steady, NO forced step): \"Your SpO₂ is steady at 97 %, right inside your usual range — nothing to act on, the good kind of boring.\"",
"- BAD (banned filler, ungrounded — do NOT write this): \"Your numbers look good. Make sure to get enough sleep and keep up regular exercise.\"",
"",
"OUTPUT FORMAT: Reply with valid JSON only, in exactly this schema. The \"summary\" field holds the complete assessment in French: 1-3 short paragraphs of 1-3 sentences each, separated by a blank line written as \\n\\n INSIDE the JSON string. A steady one-liner stays a single paragraph:",
"{ \"summary\": \"...\" }",
"",
"ARCHETYPE — SLEEP:",
"- This is nightly sleep duration. The snapshot's values are in minutes; convert to hours for your prose (e.g. 450 min = 7.5 h). Assess both the typical duration and its CONSISTENCY: a stable ~7–9 h is the favourable pattern; high night-to-night variability is itself worth naming even when the mean looks fine.",
"- Compare the recent nights to the user's own weekly/monthly baseline. A reference band of 7–9 h is a coarse adult guide, not a verdict — short or long sleepers vary.",
"- Close with one doable step toward more consistent or sufficient sleep ONLY when the finding implies one — never the forbidden 'get enough sleep' platitude; be specific (e.g. a steadier wind-down time). When sleep is already consistent and sufficient, affirm it and name one thing worth keeping an eye on instead of manufacturing a step.",
"",
"METRIC: Sleep duration (unit: min).",
"Neither extreme is good — the value should sit inside its normal band; deviations in either direction are worth noting.",
"Coarse population reference band: 420–540 min (a placement aid only — the user's OWN baseline leads).",
"",
"OUTPUT LANGUAGE: Répondez en français. Utilisez le vouvoiement par défaut ; tutoyez si l'utilisateur tutoie en premier. Utilisez un vocabulaire de santé français naturel."
],
"temperature": 0.45,
"timeoutMs": 60000
}
],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": true,
"hasProvider": false,
"text": "Stable, comme d’habitude. Sleep duration est à 423,9 min en ce moment — au-dessus de ta moyenne habituelle de 404,1 min. C’est dans tes repères habituels — rien qui appelle une réaction maintenant.",
"updatedAt": null
}
},
"VO2_MAX no-data": {
"calls": [],
"enqueued": [],
"notes": [
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "5df7980e558674aefbfe894525e4d2721f281a3dcf776465d7cc1ba0983b42fd",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "e348f34b369dce59f42c06c8bcf06a163f86dc61913f8af96d3bb5a49e55f4f6",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:BLOOD_GLUCOSE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "f9d4889e34e8decefbd5042f4e511a36493df422e8da996c3300bf24e1f2ee88",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "674e1cd14b6fcb0f502db368a80074380c0f241e2abcfc5c3829d9afdf83224e",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:RESTING_HEART_RATE",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": "2026-06-15T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "de",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "42e3295479aedb8d71869250de66ec31d8d36bbf3b2243a5f20a4b0b36dd7849",
"text": "Das ist kein JSON.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-16",
"generatedAt": "2026-06-16T10:00:00.000Z",
"inputHash": null,
"items": null,
"locale": "en",
"metric": "metric:SLEEP_DURATION",
"negativeReason": null,
"retryAt": null,
"snapshotHash": "6075377b17914e90f2c3beb7ecf88d8bd454427d0d32ab205552f79a05dd3c94",
"text": "Parity note for next-day-en.",
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "es",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
},
{
"dateKey": "2026-06-15",
"generatedAt": null,
"inputHash": null,
"items": null,
"locale": "fr",
"metric": "metric:SLEEP_DURATION",
"negativeReason": "screened",
"retryAt": "2026-06-15T10:05:00.000Z",
"snapshotHash": null,
"text": null,
"userId": "parity-rich"
}
],
"result": {
"cached": false,
"hasProvider": true,
"insufficient": true,
"text": null,
"updatedAt": null
}
}
}