Skip to content

Preserve extension profiles when cloning inherited slices - #1653

Open
glichtner wants to merge 1 commit into
FHIR:masterfrom
glichtner:fix/cloned-extension-slice-profile
Open

glichtner wants to merge 1 commit into
FHIR:masterfrom
glichtner:fix/cloned-extension-slice-profile

Conversation

@glichtner

Copy link
Copy Markdown
Contributor

Description

When a new slice constrains an extension copied from the slicing entry, SUSHI can omit the extension's profile from the differential. The snapshot generator then sees a generic Extension and loses its specific value type.

Example

// sushi-config.yaml: fhirVersion: 4.0.1, canonical: http://hl7.org/fhir/us/minimal
Extension: LinkKind
* value[x] only CodeableConcept

Profile: BasePatient
Parent: Patient
* link.extension contains LinkKind named kind 0..1
* link ^slicing.discriminator.type = #value
* link ^slicing.discriminator.path = "type"
* link ^slicing.rules = #open
* link contains replacedBy 0..*
* link[replacedBy].type = #replaced-by

Profile: DerivedPatient
Parent: BasePatient
* link contains seeAlso 0..*
* link[seeAlso].type = #seealso
* link[seeAlso].extension[kind] 1..1
* link[seeAlso].extension[kind].valueCodeableConcept.coding.code = #current

Expected: the differential for Patient.link:seeAlso.extension:kind includes type.code = Extension and type.profile = http://hl7.org/fhir/us/minimal/StructureDefinition/LinkKind, alongside min = 1.

Actual before this PR: the element contains only id, path, sliceName and min. The Java snapshot generator consequently reports “has no profile and no fixed url” and cannot resolve the constraint on value[x].coding.

Cause

SUSHI copies the extension slice into its working snapshot but retains its original differential baseline. Its identifying profile is therefore treated as unchanged and omitted, even though the extension is being declared at a new location.

Testing instructions

The FSH above is the input to declares the extension profile in a new slice in test/export/InheritedExtensionSlice.test.ts, using the same FHIR version and canonical as the test configuration.

npm test -- --runInBand test/export/InheritedExtensionSlice.test.ts

All eight exporter cases and all 3,586 suite tests pass; TypeScript and ESLint pass.

The original regression from #1609 in test/export/StructureDefinitionExporter.test.ts remains unchanged and passes. It asserts that an untouched inherited extension is omitted and the child differential contains exactly the three expected elements.

Related issues

PR #1609 introduced the _original.id assignment to prevent copied, unchanged extensions from appearing in a child differential solely because their IDs changed. This PR preserves that protection by handling ID-only relocation of the same extension in hasDiff(), instead of overwriting the original ID in cloneChildren().

Keeping the original ID allows calculateDiff() to recognize copies and include their identifying type/profile when the extension or its descendants are constrained. Unchanged copies remain omitted, and extension slices already declared in a parent profile continue to emit only their changed properties.

glichtner added a commit to Dissolve-E/awmf-ig that referenced this pull request Nov 3, 2026
publish-version.sh runs the IG Publisher itself and did not get the
SUSHI from install-sushi.sh, so a release build would use the released
SUSHI and lose the classifier profile again (FHIR/sushi#1653). It now
puts it first on PATH after the dependency builds, as
run-ig-publisher.sh does. The -go-publish rebuild runs in the same
process and uses it too, so both builds report the same QA counts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant