refactor(insights): strip release markers from the model-facing prompt

The insights ground-rules carried changelog tokens ("v1.4.16 phase B8", "W4d")
inside the prompt strings the model reads — token waste and inconsistent with
the project voice. Move the rule content to clean numbered rules; the markers
belong in code comments, not shipped prompt prose. Update the test pins to the
cleaned rule headers.

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-05 13:58:28 +02:00
1 parent 9a07a27001
commit 0193dbc1ee
2 files changed
+25 -24

No files matched your search

@@ -37,7 +37,7 @@ describe("getStrictInsightsSystemPrompt — EN", () => {
const prompt = getStrictInsightsSystemPrompt("en");
it("carries the Apple Health silent-fallback contract (rule 11)", () => {
expect(prompt).toMatch(/11\. v1\.4\.23/);
expect(prompt).toMatch(/11\. Optional Apple Health metric categories/);
expect(prompt).toMatch(/Apple Health metric categories/);
expect(prompt).toMatch(/HRV/);
expect(prompt).toMatch(/sleep duration/);
@@ -49,11 +49,12 @@ describe("getStrictInsightsSystemPrompt — EN", () => {
it("does not bake live tenant figures into the new rule", () => {
// PII rule: the Apple Health rule frames in terms of metric
// categories, never a specific number / email / username. The block
// starts at "11. v1.4.23" (renumbered when v1.4.28 dropped the
// weekly-report rule) and ends at the GUIDELINE TARGETS heading
// that closes the ground-rules section.
// starts at "11. Optional Apple Health metric categories" and ends at
// the GUIDELINE TARGETS heading that closes the ground-rules section.
const ruleAppleHealth =
prompt.split("11. v1.4.23")[1]?.split("GUIDELINE TARGETS")[0] ?? "";
prompt
.split("11. Optional Apple Health metric categories")[1]
?.split("GUIDELINE TARGETS")[0] ?? "";
expect(ruleAppleHealth.length).toBeGreaterThan(0);
expect(ruleAppleHealth).not.toMatch(/@.+\.(com|net|org|de|test)/);
// The rule mentions metric category names but no concrete sample
@@ -72,7 +73,7 @@ describe("getStrictInsightsSystemPrompt — DE", () => {
const prompt = getStrictInsightsSystemPrompt("de");
it("carries the German silent-fallback wording (rule 11)", () => {
expect(prompt).toMatch(/11\. v1\.4\.23/);
expect(prompt).toMatch(/11\. Optionale Apple-Health-Metrik-Kategorien/);
expect(prompt).toMatch(/Apple-Health-Metrik-Kategorien/);
expect(prompt).toMatch(/HRV/);
expect(prompt).toMatch(/Schlafdauer/);
@@ -100,7 +101,7 @@ describe("getStrictInsightsSystemPrompt — DE", () => {
describe("getStrictInsightsSystemPrompt — enum-identifier ban (no enum names in prose, rule 12)", () => {
it("EN prompt carries the rule and enumerates the banned identifiers", () => {
const prompt = getStrictInsightsSystemPrompt("en");
expect(prompt).toMatch(/12\. v1\.4\.25/);
expect(prompt).toMatch(/12\. Internal metric identifiers/);
expect(prompt).toMatch(/Internal metric identifiers/);
// The banned-list is enumerated verbatim so the model has no
// ambiguity about which strings are off-limits in prose.
@@ -122,7 +123,7 @@ describe("getStrictInsightsSystemPrompt — enum-identifier ban (no enum names i
it("DE prompt carries the rule with the same banned list", () => {
const prompt = getStrictInsightsSystemPrompt("de");
expect(prompt).toMatch(/12\. v1\.4\.25/);
expect(prompt).toMatch(/12\. Interne Metrik-Identifier/);
expect(prompt).toMatch(/Interne Metrik-Identifier/);
expect(prompt).toMatch(/"Pressure_Sys"/);
expect(prompt).toMatch(/"BLOOD_PRESSURE_SYS"/);
+16 -16
View File
@@ -133,14 +133,14 @@ gib die obige Verweigerung zurück.`,
language. Reference the user's actual data trends — do not paste
in placeholder text. The rationale.dataWindow MUST equal the
metricSource.timeRange so the UI's mini-chart can pin to it.
6. v1.4.16 phase B8 — when the user prompt contains a "SYSTEM
6. When the user prompt contains a "SYSTEM
CONTEXT — COMPARISON MODE ACTIVE" block, narrate the comparison
in the summary's first sentence using the prior-period numbers
that block carries. Cite the deltas verbatim — do NOT invent
comparison numbers, and do NOT extrapolate beyond the metrics
listed. When the block reports "no prior-period data available"
for every metric, state that explicitly and skip the narration.
7. v1.4.19 — Do NOT open with a compliment about the data quantity
7. Do NOT open with a compliment about the data quantity
or data quality. The user does not see what fields were sent and
reads such openers as filler. Mention data quality ONLY when it
materially limits the analysis: n<7 readings in the analyzed
@@ -150,7 +150,7 @@ gib die obige Verweigerung zurück.`,
patterns include "Your data foundation is strong", "Datengrundlage
ist sehr stark", "You have a solid baseline", "Great dataset" and
any rephrasing of the same sentiment.
8. v1.4.20 — Optional "dailyBriefing" block. When the snapshot
8. Optional "dailyBriefing" block. When the snapshot
carries enough signal (any of bp / weight / pulse / mood /
medications.compliance) emit a top-level "dailyBriefing" object
with two fields:
@@ -170,7 +170,7 @@ gib die obige Verweigerung zurück.`,
When the snapshot has no analysable data, omit "dailyBriefing"
or set it to null. Empty paragraph or filler-only findings are
rejected by the parser.
9. v1.4.20 phase B3 — Optional "trendAnnotations" block. When the
9. Optional "trendAnnotations" block. When the
snapshot has enough signal for a given metric (bp, weight, or
mood), emit a one-sentence annotation that reads directly below
the metric's small chart in the Trends row. Each annotation MUST:
@@ -185,7 +185,7 @@ gib die obige Verweigerung zurück.`,
the entire block (or set null) when no metric qualifies. Trend
annotations are SHORT — they sit below charts and compete for
attention with the chart itself; one tight sentence is the goal.
10. v1.4.20 phase B4 — Optional "storyboardAnnotations" array (max 20).
10. Optional "storyboardAnnotations" array (max 20).
When the 90-day BP timeline includes notable factual events the
user logged, emit annotations that pin to specific dates. Each
annotation MUST:
@@ -205,7 +205,7 @@ gib die obige Verweigerung zurück.`,
Date format: "YYYY-MM-DD". Label cap: 80 chars. Detail cap:
400 chars. Hard array cap: 20. Omit the field entirely when the
timeline has no notable events.
11. v1.4.23 — Optional Apple Health metric categories. When the
11. Optional Apple Health metric categories. When the
snapshot carries any of HRV, sleep duration, resting HR, step
count, active energy, flights climbed, walking/running distance,
VO2 max, or body temperature, you may reference those categories
@@ -218,7 +218,7 @@ gib die obige Verweigerung zurück.`,
the user connect a wearable. The presence or absence of the
HealthKit metric block in the snapshot is the only signal you
should act on.
12. v1.4.25 — Internal metric identifiers stay OUT of your prose.
12. Internal metric identifiers stay OUT of your prose.
Never write database / enum-style names like "Pressure_Sys",
"BLOOD_PRESSURE_SYS", "PULSE_BPM", "MOOD_SCORE",
"MEDICATION_COMPLIANCE_PCT", "HEART_RATE_VARIABILITY",
@@ -240,7 +240,7 @@ gib die obige Verweigerung zurück.`,
contract-level identifiers the parser reads — those stay in
the documented enum vocabulary exactly as listed in OUTPUT
FORMAT below. The ban applies ONLY to prose.
13. v1.4.25 W4d — NEVER prescribe or modify medication doses, even
13. NEVER prescribe or modify medication doses, even
when the snapshot reveals a named GLP-1 receptor agonist
(Mounjaro, Ozempic, Wegovy, Zepbound, Trulicity, Saxenda,
Rybelsus). Findings may NOTE the named medication and the
@@ -278,14 +278,14 @@ gib die obige Verweigerung zurück.`,
Platzhaltertext. rationale.dataWindow MUSS gleich
metricSource.timeRange sein, damit die UI das Mini-Chart auf das
gleiche Fenster fixieren kann.
6. v1.4.16 phase B8 — wenn der User-Prompt einen Block "SYSTEM
6. Wenn der User-Prompt einen Block "SYSTEM
CONTEXT — VERGLEICHSMODUS AKTIV" enthält, narrative die im Block
gelisteten Deltas im ersten Satz der Zusammenfassung. Zitiere die
Werte exakt — erfinde KEINE Vergleichszahlen und extrapoliere
nicht über die gelisteten Metriken hinaus. Wenn der Block für
alle Metriken "no prior-period data available" meldet, sag das
explizit und lass die Narration weg.
7. v1.4.19 — Beginne NICHT mit einem Kompliment über Datenmenge
7. Beginne NICHT mit einem Kompliment über Datenmenge
oder Datenqualität. Der Nutzer sieht nicht, welche Felder gesendet
wurden, und empfindet solche Eröffnungen als Füllsatz. Erwähne
Datenqualität AUSSCHLIEßLICH dann, wenn sie die Analyse
@@ -296,7 +296,7 @@ gib die obige Verweigerung zurück.`,
Verbotene Eröffnungsmuster sind unter anderem "Datengrundlage ist
sehr stark", "Your data foundation is strong", "Du hast eine solide
Baseline", "Großartiger Datensatz" und jede sinngemäße Umformulierung.
8. v1.4.20 — Optionaler "dailyBriefing"-Block. Wenn der Snapshot
8. Optionaler "dailyBriefing"-Block. Wenn der Snapshot
genügend Signal trägt (irgendwas aus bp / weight / pulse / mood /
medications.compliance), emittiere ein Top-Level-Objekt
"dailyBriefing" mit zwei Feldern:
@@ -318,7 +318,7 @@ gib die obige Verweigerung zurück.`,
Hat der Snapshot keine analysierbaren Daten, lass "dailyBriefing"
weg oder setze es auf null. Leerer Paragraph oder Findings ohne
Substanz werden vom Parser abgelehnt.
9. v1.4.20 phase B3 — Optionaler "trendAnnotations"-Block. Wenn der
9. Optionaler "trendAnnotations"-Block. Wenn der
Snapshot für eine Metrik (bp, weight oder mood) genügend Signal
trägt, emittiere eine einsätzige Annotation, die direkt unter dem
kleinen Chart der Metrik in der Trends-Reihe gelesen wird. Jede
@@ -336,7 +336,7 @@ gib die obige Verweigerung zurück.`,
Metrik qualifiziert. Trend-Annotationen sind KURZ — sie stehen unter
Charts und konkurrieren mit dem Chart selbst um Aufmerksamkeit; ein
prägnanter Satz ist das Ziel.
10. v1.4.20 phase B4 — Optionales "storyboardAnnotations"-Array
10. Optionales "storyboardAnnotations"-Array
(max 20). Wenn die 90-Tage-BP-Timeline bemerkenswerte vom Nutzer
geloggte Ereignisse enthält, emittiere Annotationen, die auf
konkrete Daten zeigen. Jede Annotation MUSS:
@@ -358,7 +358,7 @@ gib die obige Verweigerung zurück.`,
Datumsformat: "YYYY-MM-DD". Label-Cap: 80 Zeichen. Detail-Cap:
400 Zeichen. Array-Höchstgrenze: 20. Lass das Feld komplett
weg, wenn die Timeline keine bemerkenswerten Ereignisse hat.
11. v1.4.23 — Optionale Apple-Health-Metrik-Kategorien. Wenn der
11. Optionale Apple-Health-Metrik-Kategorien. Wenn der
Snapshot eine der folgenden Kategorien führt — HRV, Schlafdauer,
Ruhepuls, Schrittzahl, aktiver Energieumsatz, Stockwerke,
Geh-/Laufdistanz, VO2 max oder Körpertemperatur — kannst du diese
@@ -371,7 +371,7 @@ gib die obige Verweigerung zurück.`,
HealthKit, schlage nicht vor, ein Wearable zu verbinden. Das
Vorhandensein oder Fehlen des HealthKit-Metrik-Blocks im Snapshot
ist das einzige Signal, auf das du reagieren solltest.
12. v1.4.25 — Interne Metrik-Identifier gehören NICHT in deinen
12. Interne Metrik-Identifier gehören NICHT in deinen
Fließtext. Schreibe niemals Datenbank- bzw. Enum-Namen wie
"Pressure_Sys", "BLOOD_PRESSURE_SYS", "PULSE_BPM", "MOOD_SCORE",
"MEDICATION_COMPLIANCE_PCT", "HEART_RATE_VARIABILITY",
@@ -394,7 +394,7 @@ gib die obige Verweigerung zurück.`,
Parser liest — diese bleiben EXAKT in der unten in
AUSGABEFORMAT dokumentierten Enum-Schreibweise. Das Verbot
gilt AUSSCHLIEßLICH für Fließtext.
13. v1.4.25 W4d — Du verschreibst und änderst NIEMALS
13. Du verschreibst und änderst NIEMALS
Medikamenten-Dosen, auch wenn der Snapshot einen
GLP-1-Rezeptoragonisten namentlich benennt (Mounjaro, Ozempic,
Wegovy, Zepbound, Trulicity, Saxenda, Rybelsus). Befunde dürfen