import { describe, it, expect } from "vitest";
import { parseCompactDraft } from "../server/compact";
import { groundedFact } from "../server/guards";
const source = (text: string) => [
{ id: "note", title: "Note", kind: "Synthetic", date: "2026-10-23", text },
];
describe("real-world normalization boundaries", () => {
it.each([
[
"Medication: Metformin; strength: 500 mg; form: tablet; dose: 1 tablet; frequency: 2/day",
"Prescribed Metformin 500mg tab, 1 tab BID.",
],
[
"Medication: Metformin; dose: 0.5 tablet; frequency: 2/day",
"Metformin: half a tablet twice daily.",
],
[
"Medication: Amlodipine; strength: 2.5 mg; frequency: 1/day",
"She takes Amlodipine 2.5mg tablets once daily.",
],
[
"Lab: eGFR; value: 38; unit: mL/min/1.73m2; date: 2026-10-12",
"Her eGFR was 38 mL/min/1.73m2 on 12 October 2026.",
],
])("accepts explicitly supported normalization %s", (normalized, quote) =>
expect(groundedFact(normalized, quote)?.problem).toBeNull(),
);
it.each([
[
"Medication: Metformin; strength: 500 mg",
"Metformin 1500 mg is recorded.",
],
[
"Medication: Metformin; strength: 5 mg",
"Prescribed Metformin 500 mg and Amlodipine 5 mg.",
],
[
"Medication: Amlodipine; dose: 1 tablet",
"Metformin one tablet and Amlodipine 5 mg.",
],
[
"Lab: eGFR; value: 38; unit: mL/min/1.73m2; date: 2026-10-12",
"eGFR 38 mL/min/1.73m2 on 12/10/2026.",
],
])("rejects inferred or misattributed fields %s", (normalized, quote) =>
expect(() => groundedFact(normalized, quote)).toThrow(),
);
it.each([
["Patient: Yara Brook", "Her mother Yara Brook is 65 years old."],
["Age: 65", "Her mother Yara Brook is 65 years old."],
["Allergies: Penicillin", "She denied a Penicillin allergy."],
["Condition: asthma", "She is negative for asthma."],
[
"Medication: Metformin; strength: 500 mg",
"She does not take Metformin 500 mg.",
],
[
"Medication: Metformin; strength: 500 mg",
"She denies taking Metformin 500 mg.",
],
["Allergies: Penicillin", "Her mother has a Penicillin allergy."],
["Condition: diabetes", "Family history includes diabetes."],
[
"Medication: Ibuprofen; strength: 200 mg; frequency: 3/day",
"She takes Ibuprofen 200 mg as needed, up to three times daily.",
],
["Medication: Metformin; strength: 500 mg", "Metformin 500 mg OD."],
[
"Lab: eGFR; value: 38; unit: mL/min/1.73m2",
"Her eGFR was 38 mL/min/1.73m2.",
],
])(
"keeps ambiguous or incomplete facts out of assessment %s",
(normalized, quote) =>
expect(groundedFact(normalized, quote)?.problem).toBeTruthy(),
);
it("quarantines an unsupported generated row without discarding usable records", () => {
const sources = source(
"Patient: Amina Stone\nMedication: Metformin; strength: 500 mg\nHer eGFR was 38 mL/min/1.73m2.",
);
const d = parseCompactDraft(
{
facts: [
[3, "Lab: eGFR; value: 38; unit: mL/min/1.73m2; date: 2026-10-12"],
],
},
sources,
"test",
1,
);
expect(d.facts).toHaveLength(2);
expect(d.warnings).toHaveLength(1);
expect(d.unparsed).toHaveLength(1);
expect(d.sourceReviewRequired).toBe(true);
});
it("canonicalizes explicit tablet and capsule dose abbreviations without losing quantities", () => {
const d = parseCompactDraft(
{
facts: [
[
1,
"Medication: Metformin; strength: 500 mg; form: tab; dose: 1 tab; frequency: 2/day",
],
],
},
source("- Prescribed Metformin 500mg tab, 1 tab BID."),
"test",
1,
);
expect(d.facts[0].normalizedLine).toContain("dose: 1 tablet");
expect(d.warnings).toHaveLength(0);
});
it("retains supported medicine fields while making invented optional quantities unknown", () => {
const d = parseCompactDraft(
{
facts: [
[
1,
"Medication: Amlodipine; strength: 2.5 mg; form: tablets; dose: 1 tablet; frequency: 1/day",
],
],
},
source("She takes Amlodipine 2.5mg tablets once daily."),
"test",
1,
);
expect(d.facts).toHaveLength(1);
expect(d.facts[0].problem).toBeNull();
expect(d.facts[0].detail).toContain("Dose unknown");
expect(d.facts[0].normalizedLine).not.toContain("dose:");
expect(d.warnings?.[0].reason).toContain("Removed that field");
expect(d.warnings?.[0].normalizedLine).toContain("dose: 1 tablet");
});
it("never lets the model replace deterministic fields", () =>
expect(() =>
parseCompactDraft(
{ facts: [[1, "Patient: Other"]] },
source("Patient: Amina Stone"),
"test",
1,
),
).toThrow("locked"));
it("requires source references to exist", () =>
expect(() =>
parseCompactDraft(
{ facts: [[99, "Patient: Amina Stone"]] },
source("Amina Stone is a patient."),
"test",
1,
),
).toThrow("unknown"));
});