// What the engine adds with its clinician options on (feat/engine-clinician-context, // docs/engine-clinician-options.md), for the fixture's film patients. Fictional use of draft, // unreviewed engine output; the specific references are the ones that branch records. import type * as T from "../../src/api/types"; export const SPECIFIC_REFERENCES: Record = { "lab-metformin-egfr-45": [ { sourceId: "smpc-metformin", document: "Glucophage 500 mg film-coated tablets: UK SmPC (Merck)", section: "4.2 Posology and method of administration: renal impairment table", version: "Date of revision of the text: November 2025 (emc, updated 22 December 2025)", url: "https://www.medicines.org.uk/emc/product/987/smpc", checkedOn: "2026-10-30", says: "GFR 30-44 mL/min: total maximum daily dose 1000 mg, divided into 2-3 doses. GFR 45-59 mL/min: 2000 mg.", }, ], "allergy-penicillin": [ { sourceId: "smpc-amoxicillin", document: "Amoxicillin 500mg Capsules: UK SmPC (Aurobindo Pharma - Milpharm Ltd)", section: "4.3 Contraindications", version: "emc, updated 1 April 2025", url: "https://www.medicines.org.uk/emc/product/526/smpc", checkedOn: "2026-10-30", says: "Contraindicated with hypersensitivity to the active substance or to any of the penicillins, or a history of a severe immediate hypersensitivity reaction (for example anaphylaxis) to another beta-lactam.", appliesTo: ["amoxicillin"], }, { sourceId: "nice-cg183", document: "NICE clinical guideline CG183: Drug allergy: diagnosis and management", section: "Recommendations 1.2.2 and 1.2.6", version: "Published 3 September 2014", url: "https://www.nice.org.uk/guidance/cg183/chapter/Recommendations", checkedOn: "2026-10-30", says: "Record the drug, the signs, symptoms and severity of the reaction and its date; check and confirm drug allergy status before prescribing.", }, ], }; type Result = T.CheckRun["assessment"]["contextual"]; const bp = /amlodipine|lisinopril|losartan|nifedipine/i; /** * Decorate a plain engine result as the options would: clinician wording marked draft, rule review, * specific references, the allergy reaction, monitoring medicines, the metformin kidney limit and * coverage lines. `reactions` maps an allergy to its shared detail (from MARMAR Health). */ export function withEngineOptions( result: Result, wording: Record, reactions: Record, medicines: { id: string; label: string; detail: string }[], coverageLines: string[], egfr: { value: number; date: string } | null, ): Result & T.EngineResultExtras { const findings = result.findings.map((f): typeof f & T.EngineFindingExtras => { const extra: T.EngineFindingExtras = { clinician_title: wording[f.id]?.title, clinician_why: wording[f.id]?.explanation, clinician_wording_review: "draft", rule_review: "not_in_accepted_sign_off", specific_references: SPECIFIC_REFERENCES[f.ruleId] ?? [], }; if (f.kind === "allergy") { const allergy = result.what_we_checked.allergies[0] ?? "Penicillin"; const detail = reactions[allergy.toLowerCase()] ?? null; const mild = !!detail?.reaction && /^(hives|rash|itch|itching|itchy rash)$/i.test(detail.reaction); extra.allergy_reaction = { allergy, reaction: detail?.reaction ?? null, reaction_kind: null, onset: detail?.onset === "immediate" || detail?.onset === "delayed" || detail?.onset === "unknown" ? detail.onset : null, severity: null, year: detail?.year ?? null, reaction_class: mild ? "not_severe" : "unknown", }; extra.tier_without_reaction = f.tier; if (!mild) return { ...f, ...extra, tier: "get_help_now" }; } return { ...f, ...extra }; }); const tests = result.tests_to_ask_about.map((t) => ({ ...t, medicines: medicines .filter((m) => t.why.toLowerCase().includes(m.label.toLowerCase()) || (/blood pressure/i.test(t.test) && bp.test(m.label))) .map((m) => ({ id: m.id, name: m.label })), rule_ids: [t.source_id], })); // CHK-11: the Glucophage SmPC bands; at 60 and over the usual maximum applies, as before. const band = !egfr ? null : egfr.value < 30 ? { band: "under 30", max: null } : egfr.value < 45 ? { band: "30-44", max: 1000 } : egfr.value < 60 ? { band: "45-59", max: 2000 } : null; const dose = result.dose_check.map((d) => { if (!/metformin/i.test(d.medicine) || !band || !egfr) return d; const med = medicines.find((m) => m.label.toLowerCase() === d.medicine.toLowerCase()); const strength = Number(/(\d+)\s*mg/i.exec(med?.detail ?? "")?.[1] ?? 0); const units = Number(/(\d+(?:\.\d+)?)\s*(tablet|capsule)/i.exec(med?.detail ?? "")?.[1] ?? 0); const perDay = Number(/(\d+(?:\.\d+)?)\/day/.exec(med?.detail ?? "")?.[1] ?? 0); const daily = strength && units && perDay ? strength * units * perDay : null; const over = band.max === null || (daily !== null && daily > band.max); return { ...d, status: over ? ("above_limit" as const) : ("within_usual_range" as const), plain: band.max === null ? `The label lists metformin as not for use at eGFR under 30 mL/min.` : `${over ? "Above" : "Within"} the label's limit for eGFR ${band.band} mL/min (${band.max.toLocaleString("en")} mg a day). This does not confirm the right dose to take.`, kidney_limit: { ingredient: "metformin", egfr: egfr.value, egfr_comparator: null, egfr_observed_at: egfr.date, egfr_calculated: false, band: band.band, max_daily_mg: band.max, daily_mg: daily, source_id: "smpc-metformin", section: "4.2" }, }; }); return { ...result, findings, tests_to_ask_about: tests, dose_check: dose, clinician: { options_version: "0.1.0-draft", options: { clinicianWording: true, allergyTiers: true, kidneyDoseLimits: true, monitoringMedicines: true, coverage: true, specificReferences: true }, wording_review: "draft", plain: "Clinician wording and options are drafts until the clinical safety lead signs them off." }, coverage: { products_not_checked: [], facts_not_read: [], facts_missing: [], rules_waiting_for_review: findings.map((f) => ({ rule_id: f.ruleId, kind: "table" as const, review: "not_in_accepted_sign_off" as const, medicines: f.medicines, ran: true })), check_ins: { read: false, plain: "Answers from check-ins are recorded as notes; no rule reads them." }, lines: coverageLines, }, }; }