feat(ai): warm the assessment voice toward a motivating advisor

The per-metric and wellness-score assessment prompts gain a premium-advisory
layer: name the earned win, build a little momentum, frame an unfavourable
finding as an opportunity, and close forward-looking. Every existing guard
stays in force — no platitudes, no bare number-echoing, autonomy-supporting,
never alarming, moralising or diagnostic, and the banned-opener and
forbidden-phrase lists are unchanged. The composite-score archetype warms to
a WHOOP/Oura-style recovery coach while staying descriptive, not clinical.

PROMPT_VERSION 5.0.0 -> 5.1.0 so the provenance can slice prose before/after
the tone edit. Cached accounts converge to the new voice within ~24h.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.8 committed 2026-06-07 18:03:56 +02:00
1 parent e9171c1e5f
commit 9ac5df42c8
2 files changed
+20 -9

No files matched your search

+14 -5
View File
@@ -14,8 +14,13 @@ import type { Locale } from "@/lib/i18n/config";
* `current · baseline · signed delta · spread · outsideNormalSwing`
* descriptor and the prompt leads from it instead of asking the model to
* derive the comparison from raw buckets.
* 5.1.0 — premium tone pass: the assessment voice warms toward a motivating,
* forward-looking advisor (name the earned win, build momentum, frame an
* unfavourable finding as an opportunity) while every existing guard stays —
* no platitudes, no bare number-echoing, autonomy-supporting, never alarming /
* moralising / diagnostic, and the banned-opener / forbidden-phrase lists hold.
*/
export const PROMPT_VERSION = "5.0.0" as const;
export const PROMPT_VERSION = "5.1.0" as const;
/**
* Base system prompt for the per-metric Insights *assessment* cards.
@@ -115,16 +120,20 @@ const ASSESSMENT_SECTIONS: readonly AssessmentSection[] = [
},
{
id: "tone",
en: `TONE:
en: `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. Do not downplay, do not dramatise.`,
de: `TONALITÄT:
- 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.`,
de: `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. Nicht verharmlosen, nicht dramatisieren.`,
- 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.`,
},
{
id: "length",
@@ -69,14 +69,16 @@ function scoreSystemPrompt(locale: SupportedLocale): string {
const base = getBaseSystemPrompt(locale);
const section =
locale === "en"
? `ARCHETYPE — COMPOSITE WELLNESS SCORE:
? `ARCHETYPE — COMPOSITE WELLNESS SCORE (write like a premium recovery coach — WHOOP / Oura — who genuinely wants this person to do well):
- This is a 0–100 composite score, not a raw measurement. Explain WHY it sits where it does by naming the 1–2 contributors in \`signal.contributors[]\` that moved it most — a lower contributor value drags the score down. Each contributor is itself 0–100.
- Lead with the score and its standing, then attribute it to the contributor(s). Do not invent a contributor that is not listed. When there are no contributors, use the trend (signal.delta) instead.
- This is a daily wellness proxy, not a clinical or training-recovery verdict. Stay descriptive, never diagnostic.`
: `ARCHETYP — ZUSAMMENGESETZTER WELLNESS-SCORE:
- Warm and motivating: on a strong score, name the win and what it sets them up to do today; on a softer score, frame it as a recovery cue and one small thing within reach — supportive, never deflating. The encouragement is earned by the contributors / trend, never a reflexive compliment, and never bare number-echoing.
- This is a daily wellness proxy, not a clinical or training-recovery verdict. Stay descriptive, never diagnostic, never alarming.`
: `ARCHETYP — ZUSAMMENGESETZTER WELLNESS-SCORE (schreibe wie ein Premium-Recovery-Coach — WHOOP / Oura —, der dieser Person echten Erfolg wünscht):
- Das ist ein 0–100-Kompositscore, keine Rohmessung. Erkläre, WARUM er dort liegt, indem du die 1–2 Beiträge aus \`signal.contributors[]\` nennst, die ihn am stärksten bewegt haben — ein niedriger Beitragswert zieht den Score nach unten. Jeder Beitrag ist selbst 0–100.
- Führe mit dem Score und seiner Einordnung, dann ordne ihn den Beiträgen zu. Erfinde keinen Beitrag, der nicht gelistet ist. Gibt es keine Beiträge, nutze stattdessen den Trend (signal.delta).
- Das ist ein täglicher Wellness-Indikator, kein klinisches Urteil und keine Trainings-Recovery-Bewertung. Bleibe beschreibend, nie diagnostisch.`;
- Warm und motivierend: bei einem starken Score den Erfolg benennen und was er heute ermöglicht; bei einem schwächeren Score als Erholungshinweis einordnen und eine kleine, erreichbare Sache nennen — unterstützend, nie entmutigend. Die Ermutigung ist durch die Beiträge / den Trend verdient, nie ein reflexhaftes Kompliment und nie bloße Zahlenwiederholung.
- Das ist ein täglicher Wellness-Indikator, kein klinisches Urteil und keine Trainings-Recovery-Bewertung. Bleibe beschreibend, nie diagnostisch, nie alarmierend.`;
return `${base}\n\n${section}`;
}