Skip to content

Conversation

@cmoesel
Copy link
Member

@cmoesel cmoesel commented Dec 10, 2025

Description: SUSHI already supported removing uninheritable SD extensions. Now we apply similar logic to remove uninheritable extensions from EDs.

I've run a full regression on this code. Of 1000+ FSH projects, only 28 are affected by this change. Here is a summary of the changes:

  • structuredefinition-explicit-type-name added to differential: The most common affect of this PR is that many projects who declared a structuredefinition-explicit-type-name extension in their FSH now have it properly reflected in their differentials. Prior to this change, if a profile specified a structuredefinition-explicit-type-name on an element that matched one from the parent's element, SUSHI suppressed it from the differential. Since it is marked as an uninherited extension now, however, SUSHI puts it in the differential. This change was found in the following projects: HL7-cz/img, hl7-eu/dcc, hl7-eu/xpandh-ps, HL7-cz/img-order, gatekeeper-project/poc-ai-gk, HL7-cz/lab-order, hl7-eu/xpandh-hdr, hl7-eu/x-ehealth, gatekeeper-project/gk-fhir-ig, HL7-cz/ps, HL7-cz/cz-ems, hl7-eu/eps, HL7-cz/DIGOVO, HL7-cz/hdr, hl7-eu/pcsp, hl7-it/dgc, HL7/fhir-us-ph-library, IHE/PCC.mAPS, hl7-eu/hdr, HL7/fhir-health-care-surveys-reporting-ig, HL7/livd, IHE/PCC.RIPT.
  • structuredefinition-standards-status added to differential: Similar to above, SUSHI previously suppressed the structuredefinition-standards-status extension if it matched an extension in the same element on the parent. Since structuredefinition-standards-status is marked as an uninherited extension, however, SUSHI will now put it in the differential if the child has specified it. The change was found in one project: BIH-CEI/UTN.
  • structuredefinition-explicit-type-name removed from differential: In some cases, if additional extensions were added to an element that already had a structuredefinition-explicit-type-name extension on it, that structuredefinition-explicit-type-name would be put into the differential. Since it is now marked as an extension that should not be inherited, however, SUSHI no longer puts it into the differential if it is specified only in the parent. This change was found in the following projects: HL7-cz/img, hl7au/au-fhir-erequesting, HL7-cz/cz-lab, HL7-cz/hdr, hl7-eu/hdr, HL7/fhir-ips, HL7Austria/ELGA-MOPED-R5
  • structuredefinition-standards-status removed from differential: Similar to above, sometimes the structuredefinition-standards-status extension from the parent would be put into the differential of a child profile. This no longer happens since structuredefinition-standards-status is marked as an uninherited extension. This change was found in the following projects: HL7-cz/img, HL7-cz/cz-lab, IKNL/PZP-FHIR-R4.
  • structuredefinition-normative-version removed from differential: Similar to above, sometimes the structuredefinition-normative-version extension from the parent would be put into the differential of a child profile. This no longer happens since structuredefinition-normative-version is marked as an uninherited extension. This change was found in ony one project: IKNL/PZP-FHIR-R4.
  • inherited obligations extension overwritten: In one project, the FSH sets a structuredefinition-explicit-type-name extension by index 0 (e.g., * ^extension[0].url = "http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name"). This used to overwrite the structuredefinition-explicit-type-name inherited from the parent, but since that extension is no longer inherited, it now overwrites a different (obligation) extension -- causing an invalid extension. This can (and should) be fixed by using the special extension path syntax (e.g., * ^extension[$explicit-type-name].valueString = "Section", assuming $explicit-type-name is an alias for http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name).

Testing Instructions: The unit tests prove that this is working, but if you want to try it manually, make a SUSHI project with FSH like this:

Profile: SpecialCodeableConcept
Parent: CodeableConcept
Description: "A CodeableConcept profile with an uninheritable extension on text"
// the structuredefinition-standards-status extension should not be inherited in child profiles
* text ^extension[http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status].valueCode = #draft
// the elementdefinition-question can be inherited in child profiles
* text ^extension[http://hl7.org/fhir/StructureDefinition/elementdefinition-question].valueString = "What does the code mean?"

Profile: SpecialCodeableConceptChild
Parent: SpecialCodeableConcept
Description: "A child of SpecialCodeableConcept that should not inherit the uninheritable extension"
* text 1..1

Profile: ObservationWithSpecialCode
Parent: Observation
Description: "An Observation that constrain code to SpecialCodeableConcept and walks into it"
* code only SpecialCodeableConcept
// Walk into the code element so its sub-elements (e.g., text) get copied over.
// The uninheritable extension should not be copied over as part of this process.
* code.text 1..1

Run the currently released SUSHI against this project using snapshot mode (e.g., sushi build --snapshot /path/to/fsh/project). When you do:

  • The SpecialCodeableConcept profile will have three extensions on the CodeableConcept.text element in the snapshot.
  • The SpecialCodeableConceptChild profile will also have those three extensions on the CodeableConcept.text element in the snapshot.
  • The ObservationWithSpecialCode profile will have those three same extensions on the Observation.code.text element in the snapshot.

Now run this PR version of SUSHI agains the same project (e.g., ts-node src/app.ts build --snapshot /path/to/fsh/project). When you do:

  • The SpecialCodeableConcept profile will still have the three extensions on the CodeableConcept.text element in the snapshot because it is the original.
  • The SpecialCodeableConceptChild profile will only have two extensions on the CodeableConcept.text element in the snapshot because there is one extension (structuredefinition-standards-status) that was not inherited.
  • The ObservationWithSpecialCode profile will also only have two extensions on the Observation.code.text element in the snapshot because it did not inherit the structuredefinition-standards-status extension.

If you would like to run a regression on only the projects that have changed, you may use this command: npm run regression -- run -a gh:master -b local --repo BIH-CEI/UTN#main HL7-cz/img#master hl7au/au-fhir-erequesting#master HL7-cz/cz-lab#master hl7-eu/dcc#master hl7-eu/xpandh-ps#master HL7-cz/img-order#master gatekeeper-project/poc-ai-gk#master HL7-cz/lab-order#master hl7-eu/xpandh-hdr#master hl7-eu/x-ehealth#master gatekeeper-project/gk-fhir-ig#master HL7-cz/ps#master HL7-cz/cz-ems#master hl7-eu/eps#master IKNL/PZP-FHIR-R4#main HL7-cz/DIGOVO#master HL7-cz/hdr#main hl7-eu/pcsp#master hl7-it/dgc#master HL7/fhir-us-ph-library#master IHE/PCC.mAPS#master hl7-eu/hdr#master HL7/fhir-health-care-surveys-reporting-ig#master HL7/fhir-ips#master HL7/livd#master HL7Austria/ELGA-MOPED-R5#main IHE/PCC.RIPT#master

Related Issue: N/A

SUSHI already supported removing uninheritable SD extensions. Now we apply similar logic to remove uninheritable extensions from EDs.
@cmoesel cmoesel requested a review from jduteau December 10, 2025 18:25
@cmoesel cmoesel merged commit f579da9 into master Dec 27, 2025
14 checks passed
@cmoesel cmoesel deleted the uninherited-element-extensions branch December 27, 2025 19:05
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.

3 participants