feat(validator): warn when a known extension sits outside its declared context - #616
feat(validator): warn when a known extension sits outside its declared context#616angela-helios wants to merge 5 commits into
Conversation
…d context Per FHIR's extension-definition rules, StructureDefinition.context pins where an extension may be used — an element-type context names one exact spot (Patient is the resource root, Patient.name that element), not 'anywhere in the resource'. The editor picker already honored this; the validation engine never looked, so a resource carrying a known extension in the wrong place passed $validate silently. The walk now checks each extension/modifierExtension item whose url resolves to a schema with declared contexts against the index-free parent element path, and reports a warning-severity ExtensionContext issue on mismatch. Deliberately conservative: only contexts that read as resource-rooted element paths are judged — datatype names, the Element/Resource/DomainResource catch-alls, and FHIRPath expressions make the extension unjudgeable here and pass silently, as do unknown and relative (sub-extension) urls. Warnings map to warning-severity OperationOutcome issues at $validate and never trip enforce mode. The editor's issue count blocks saving, so it now keeps only error-severity issues — context guidance belongs to $validate, not between the user and their save button. Closes #615
…perationOutcome arm CI caught what the local check runs missed: the context check's membership test reads as contains(), and rest's exhaustive ErrorKind-to-IssueType match needs an arm for ExtensionContext — mapped to invalid, placement being a content problem rather than a structural one.
The spec-examples sweep falsified the always-on design twice over. Element-level judging broke on recursive elements (an instance path Questionnaire.item.item never equals the declared Questionnaire.item — matching needs the StructureDefinition path, which the walk does not have). And even root-only judging flagged hundreds of published spec resources: HL7's own publisher places the structuredefinition-wg/-fmm/ -standards-status metadata extensions on CodeSystem/ValueSet roots throughout the spec, so a faithful check marks canonical content wholesale. The check now judges resource-root extensions only and runs behind ValidationOptions::check_extension_context, default off — available to a profile author who asks, invisible to everyone else. The sweep pins the default path: all three baselines unchanged. Also fixes the duplicated test attribute the first push carried.
72b4d93 to
57c888a
Compare
|
The spec-examples sweep rejected the always-on design, and it was right to — updating the PR's claims:
So the check landed as: resource-root extensions only, behind Also for the record: an earlier push accidentally committed the re-downloaded R6 example corpus (1,375 files of line-ending churn from |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Closes #615. The gap surfaced in Steve and Angela's extension-authoring session: the picker constrains placement,
$validatenever did.What it does
The walk checks each
extension/modifierExtensionitem whose url resolves to a registry schema with declared contexts against the index-free parent element path (Patient,Patient.name), and reports a warning-severityExtensionContextissue on mismatch. Element-type contexts name one exact spot —Patientis the resource root, not "anywhere in Patient".Deliberately conservative
Judged only when every declared context reads as a resource-rooted element path. Datatype-named contexts (
HumanName), theElement/Resource/DomainResourcecatch-alls, and FHIRPath expressions make the extension unjudgeable here (the parent's type is not in hand during the walk) and pass silently — as do unknown urls and relative sub-extension urls. No false positives by construction; the common miss (a Patient extension pasted into an Observation) is caught.Severity plumbing
$validate(existingrest/validation.rsmapping) and never trip enforce mode (which rejects on error-severity only).$validate, not between the user and the save button.Tests
extension_context_mismatch_warns: birthPlace at the Patient root → silent; on an Observation → exactly one warning atObservation.extension.0; unknown url → silent. Runs against the real R4 core registry.cargo test -p helios-fhir-validator(conformance fixtures included) and-p helios-uigreen; clippy clean.