fix(insights): stop the daily briefing vanishing on grounded vitals

The daily-briefing number-grounding gate strips the whole dailyBriefing block
to null when it finds a restated figure it cannot trace to a pre-computed
server value. Its allow-set covered signalsOfDay plus the glucose / labs /
preventive-care / workout / grip / waist / pain aggregates, but omitted the
core vitals blocks — weight, blood pressure, pulse, body fat, mood, sleep,
activity, rate-pressure product, seasonal variation, historical comparison —
even though the briefing prompt is fed all of them.

A verdict-first briefing that restated a blood-pressure average or a resting
pulse (figures every BP-tracking user has) therefore tripped the gate on every
run: one ungrounded number strips the entire briefing while the rest of the
insight refreshes, so the surface reads as "every other text updated, only the
briefing is gone".

Admit every figure the server pre-computes for those blocks into the allow-set.
The anti-fabrication guarantee is unchanged — only server-computed numbers are
ever added, so a genuinely invented value is still flagged and stripped.
This commit is contained in:
Marc-André Bombeck committed 2026-07-01 18:51:36 +02:00
1 parent 13028a2605
commit bb72cbe092
2 files changed
+167

No files matched your search

@@ -196,3 +196,69 @@ describe("W8 aggregate-block grounding extension", () => {
expect(found.map((f) => f.value)).toContain(250);
});
});
// v1.25.13 — the allow-set previously omitted the CORE vitals blocks (weight,
// blood pressure, pulse, mood, sleep, …) even though the briefing prompt is fed
// all of them. A verdict-first briefing that restated a blood-pressure average
// or a resting pulse — figures every BP-tracking user has — tripped the gate and
// got the WHOLE dailyBriefing stripped to null while the rest of the insight
// refreshed. These lock in that those figures are now grounded.
describe("core-vitals grounding extension", () => {
const signals = [signal({})];
it("flags blood-pressure + pulse figures when only signals are passed", () => {
const found = findUngroundedBriefingNumbers(
{
paragraph:
"Your blood pressure has averaged 128/82 with a resting pulse near 68.",
},
signals,
);
// Without the features block these are ungrounded (the pre-fix strip).
// (82 is omitted from the assertion — it collides with the default weight
// signal's `latest: 82`, so it grounds coincidentally; 128 + 68 do not.)
expect(found.map((f) => f.value)).toEqual(
expect.arrayContaining([128, 68]),
);
});
it("admits blood-pressure + pulse averages once the features block is passed", () => {
const found = findUngroundedBriefingNumbers(
{
paragraph:
"Your blood pressure has averaged 128/82 with a resting pulse near 68.",
},
signals,
{
bloodPressure: { avgSys30: 128, avgDia30: 82 },
pulse: { avg30: 68 },
} as never,
);
expect(found).toEqual([]);
});
it("admits weight, mood and sleep means from the features block", () => {
const found = findUngroundedBriefingNumbers(
{
paragraph:
"Weight sits at 84.5 kg, your mood averaged 3.8 and you slept 7.2 hours.",
},
signals,
{
weight: { latest: 84.5, bmi: 26.1 },
mood: { avg30: 3.8 },
sleep: { avg7: 7.2 },
} as never,
);
expect(found).toEqual([]);
});
it("still flags a genuinely fabricated vital absent from every block", () => {
const found = findUngroundedBriefingNumbers(
{ paragraph: "Your systolic spiked to 195 overnight." },
signals,
{ bloodPressure: { avgSys30: 128, avgDia30: 82 } } as never,
);
expect(found.map((f) => f.value)).toContain(195);
});
});
+101
View File
@@ -176,6 +176,107 @@ function authoritativeValues(
push(pain.avg30);
push(pain.slope30);
}
// v1.25.13 — the core vitals blocks (weight, blood pressure, pulse, body
// fat, mood, sleep, activity, RPP, seasonal, historical) are ALL fed to the
// briefing prompt, but the allow-set only admitted signalsOfDay + the W8/
// clinical aggregates — so a verdict-first briefing that restated a blood-
// pressure average or a resting pulse (values every BP-tracking user has)
// tripped the gate and got the WHOLE dailyBriefing stripped to null while
// the rest of the insight refreshed. Admit every figure the server actually
// pre-computed for these blocks; the anti-fabrication guarantee is intact
// (only server-computed numbers are ever added to the set).
const weight = features.weight;
if (weight) {
push(weight.latest);
push(weight.avg7);
push(weight.avg30);
push(weight.avg90);
push(weight.allTimeAvg);
push(weight.allTimeMin);
push(weight.allTimeMax);
push(weight.slope30);
push(weight.bmi);
}
const bp = features.bloodPressure;
if (bp) {
push(bp.avgSys30);
push(bp.avgDia30);
push(bp.avgSys90);
push(bp.avgDia90);
push(bp.allTimeAvgSys);
push(bp.allTimeAvgDia);
push(bp.allTimeMinSys);
push(bp.allTimeMaxSys);
push(bp.allTimeMinDia);
push(bp.allTimeMaxDia);
push(bp.slopeSys30);
push(bp.slopeDia30);
push(bp.sdSys30);
push(bp.sdDia30);
push(bp.pulsePressure30);
push(bp.pctInTarget);
}
const pulse = features.pulse;
if (pulse) {
push(pulse.avg7);
push(pulse.avg30);
push(pulse.avg90);
push(pulse.allTimeAvg);
push(pulse.allTimeMin);
push(pulse.allTimeMax);
push(pulse.slope30);
}
const bodyFat = features.bodyFat;
if (bodyFat) {
push(bodyFat.latest);
push(bodyFat.avg30);
push(bodyFat.slope30);
}
const mood = features.mood;
if (mood) {
push(mood.avg7);
push(mood.avg30);
push(mood.latest);
}
const sleep = features.sleep;
if (sleep) {
push(sleep.avg7);
push(sleep.avg30);
push(sleep.latest);
}
const activity = features.activity;
if (activity) {
push(activity.avg7);
push(activity.avg30);
push(activity.latest);
}
const rpp = features.ratePressureProduct;
if (rpp) {
push(rpp.rpp7);
push(rpp.rpp30);
}
const seasonal = features.seasonalVariation;
if (seasonal) {
push(seasonal.winterAvgSys);
push(seasonal.summerAvgSys);
push(seasonal.delta);
}
const hist = features.historicalComparison;
if (hist) {
for (const block of [
hist.weight,
hist.systolic,
hist.diastolic,
hist.pulse,
]) {
if (block) {
push(block.current7dAvg);
push(block.previous30dAvg);
push(block.change);
}
}
}
}
return values;