fix(medications): widen the medication-effect intervals to a week of lag

The automatic Newey-West rule gives a lag of 3 on 30 to 270 daily
values, which leaves most of a physiological series' carry-over out of
the intervals. The lag is now at least 7. Reference values are
recomputed with statsmodels at the new default, and the lag-3 values
stay pinned with an explicit lag. A fit whose residual autocorrelation
exceeds 0.5 is flagged, and the card, the clinician view and the PDF
say the ranges may still be too narrow.
This commit is contained in:
Marc-André Bombeck committed 2026-10-21 23:20:28 +02:00
1 parent 99dfd68aad
commit cfd7c18d48
19 files changed
+208 -31

No files matched your search

@@ -167,6 +167,11 @@ export function MedicationEffectSection({
e.days.excludedLowAdherence + e.days.excludedNotTaking,
})}
</p>
{e.fit?.autocorrelationCaveat ? (
<p className="text-muted-foreground text-xs">
{t("medications.efficacy.segmented.autocorrelation")}
</p>
) : null}
{e.confounders.map((c) => (
<p
key={`${c.medicationName}:${c.event}:${c.date}`}
@@ -37,7 +37,8 @@ const present: EfficacySegmented = {
df: 146,
rSquared: 0.6,
residualAutocorrelation: 0.3,
hacLag: 4,
hacLag: 7,
autocorrelationCaveat: false,
},
confounders: [
{ medicationName: "Example B", event: "started", date: "2026-02-10" },
@@ -70,6 +71,20 @@ describe("ChangeAtStartSummary", () => {
expect(html).toContain("describes the starting dose");
expect(html).toContain("Example B started on");
expect(html).not.toMatch(/work(s|ing)|effective|successful/i);
expect(html).not.toContain("medication-wirkung-autocorrelation");
});
it("warns when the daily values carry over strongly", () => {
const html = render({
...present,
fit: {
...present.fit!,
residualAutocorrelation: 0.7,
autocorrelationCaveat: true,
},
});
expect(html).toContain("medication-wirkung-autocorrelation");
expect(html).toContain("even these ranges may be too narrow");
});
it("names the missing floor instead of a number", () => {
@@ -125,6 +125,14 @@ export function ChangeAtStartSummary({
{t("medications.efficacy.segmented.notTracked")}
</p>
) : null}
{segmented.fit?.autocorrelationCaveat ? (
<p
className="text-muted-foreground text-xs"
data-slot="medication-wirkung-autocorrelation"
>
{t("medications.efficacy.segmented.autocorrelation")}
</p>
) : null}
{segmented.window.endReason === "dose_change" ? (
<p className="text-muted-foreground text-xs">
{t("medications.efficacy.segmented.endDoseChange")}