From 87526e3df64ca3cfaf0c2a945bc08204c816d7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 26 Sep 2026 13:29:45 +0200 Subject: [PATCH] fix(fhir): code the body-site side with active SNOMED CT qualifiers The HL7 validator reports 419161000 and 419465000, the left and right concepts of the R4 bodysite-laterality value set, as inactive. Use the active qualifier values 7771000 Left and 24028007 Right, with 51440002 Right and left. The side word in bodySite.text stays English, the language of every other generated text in the Bundle; the builder takes no locale. --- .../__tests__/condition-body-site.test.ts | 14 +++++++--- src/lib/fhir/__tests__/conformance.test.ts | 4 +-- src/lib/fhir/resources/conditions.ts | 27 +++++++++++++------ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/lib/fhir/__tests__/condition-body-site.test.ts b/src/lib/fhir/__tests__/condition-body-site.test.ts index 8d44b95c1..46cc15861 100644 --- a/src/lib/fhir/__tests__/condition-body-site.test.ts +++ b/src/lib/fhir/__tests__/condition-body-site.test.ts @@ -51,9 +51,9 @@ describe("conditionsFromReportData — bodySite", () => { }); it.each([ - ["LEFT", "419161000", "Unilateral left", "left"], - ["RIGHT", "419465000", "Unilateral right", "right"], - ["BOTH", "51440002", "Bilateral", "both sides"], + ["LEFT", "7771000", "Left", "left"], + ["RIGHT", "24028007", "Right", "right"], + ["BOTH", "51440002", "Right and left", "both sides"], ])( "carries %s as SNOMED %s on a contained BodyStructure", (laterality, code, display, sideText) => { @@ -91,6 +91,14 @@ describe("conditionsFromReportData — bodySite", () => { expect(c.bodySite?.[0]?.coding).toBeUndefined(); }); + it("writes the side in the Bundle's language and the site in the user's words", () => { + const c = conditionFor({ bodySite: "Knie", laterality: "LEFT" }); + expect(c.bodySite?.[0]?.text).toBe("Knie (left)"); + // The same language as the rest of the generated Condition text. + expect(c.note?.[0]?.text).toMatch(/^Self-recorded /); + expect(c.contained?.[0]?.location?.text).toBe("Knie"); + }); + it("falls back to the site alone for an unknown side value", () => { const c = conditionFor({ bodySite: "Knee", laterality: "SIDEWAYS" }); expect(c.bodySite).toEqual([{ text: "Knee" }]); diff --git a/src/lib/fhir/__tests__/conformance.test.ts b/src/lib/fhir/__tests__/conformance.test.ts index 7e423e1ef..195e5f618 100644 --- a/src/lib/fhir/__tests__/conformance.test.ts +++ b/src/lib/fhir/__tests__/conformance.test.ts @@ -194,9 +194,9 @@ describe("Condition.bodySite", () => { const structure = condition.contained?.find((c) => `#${c.id}` === target); expect(structure?.resourceType).toBe("BodyStructure"); expect(structure?.patient.reference).toBe(patientUrl); - // A code from the R4 core bodysite-laterality value set. + // An active SNOMED CT laterality qualifier value. expect( - ["419161000", "419465000", "51440002"].includes( + ["7771000", "24028007", "51440002"].includes( structure?.locationQualifier?.[0]?.coding?.[0]?.code ?? "", ), ).toBe(true); diff --git a/src/lib/fhir/resources/conditions.ts b/src/lib/fhir/resources/conditions.ts index 6728b2179..a97effba8 100644 --- a/src/lib/fhir/resources/conditions.ts +++ b/src/lib/fhir/resources/conditions.ts @@ -21,19 +21,23 @@ import { SNOMED_SYSTEM, patientRef } from "@/lib/fhir/resources/common"; const DISEASE_SNOMED = { code: "64572001", display: "Disease" } as const; /** - * The side of a body site, as SNOMED CT laterality qualifiers from the R4 core - * value set `http://hl7.org/fhir/ValueSet/bodysite-laterality` - * (https://hl7.org/fhir/R4/valueset-bodysite-laterality.html); the same three - * concepts sit in `bodystructure-relative-location`, the value set R4 binds to - * `BodyStructure.locationQualifier`. Keyed on the `Laterality` enum. + * The side of a body site, as active SNOMED CT laterality qualifier values: + * 7771000 Left, 24028007 Right, 51440002 Right and left. These are the codes + * of the HL7 mCODE Laterality Qualifier value set + * (https://build.fhir.org/ig/HL7/fhir-mCODE-ig/ValueSet-mcode-laterality-qualifier-vs.html). + * The R4 core `bodysite-laterality` value set lists 419161000 / 419465000 for + * left / right, but the HL7 validator reports both as inactive in current + * SNOMED CT, so they are not used. R4 binds `BodyStructure.locationQualifier` + * with example strength, so any SNOMED CT qualifier is conformant there. + * Keyed on the `Laterality` enum. */ const LATERALITY_SNOMED: Record< string, { code: string; display: string; text: string } > = { - LEFT: { code: "419161000", display: "Unilateral left", text: "left" }, - RIGHT: { code: "419465000", display: "Unilateral right", text: "right" }, - BOTH: { code: "51440002", display: "Bilateral", text: "both sides" }, + LEFT: { code: "7771000", display: "Left", text: "left" }, + RIGHT: { code: "24028007", display: "Right", text: "right" }, + BOTH: { code: "51440002", display: "Right and left", text: "both sides" }, }; /** @@ -58,6 +62,13 @@ const BODY_STRUCTURE_ID = "bodysite-1"; * `locationQualifier` holds the SNOMED CT side. The side is also written into * `bodySite.text`, because a receiver that ignores extensions must still read * "Knee (left)" rather than a bare "Knee". + * + * The side word is English on purpose. The builder takes no locale + * (`FhirBuildOptions` carries none, unlike the PDF path), and every other + * generated text in the Bundle is English: section titles, the Condition note, + * the narratives. The site stays in the words the user wrote, so a German + * record reads "Knie (left)", the same mix as a German label beside the + * English "Self-recorded … condition journal entry" note. */ function bodySiteOf( bodySite: string | null | undefined,