marmar-context / web / context / test / compact.test.ts
compact.test.ts
Raw
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"));
});