Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConstraintGenerator should handle versioned extension canonicals #3654

Closed
lmsurpre opened this issue May 20, 2022 · 1 comment
Closed

ConstraintGenerator should handle versioned extension canonicals #3654

lmsurpre opened this issue May 20, 2022 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@lmsurpre
Copy link
Member

lmsurpre commented May 20, 2022

Describe the bug
For #3653 I'd like to ensure that when an instance is validated against a formulary profile from version 1.0.1 of that IG, then the extensions in that instance are conformant to version 1.0.1 of the corresponding extension definition.

To accomplish this, I tried adding a version postfix to the type.profile on the element definition in the profile definition.
For example, from StructureDefinition-usdf-CoveragePlan:

            {
                "id": "List.extension:usdf-Network-extension",
                "path": "List.extension",
                "sliceName": "usdf-Network-extension",
                "min": 1,
                "max": "*",
                "type": [
                    {
                        "code": "Extension",
                        "profile": [
                            "http://hl7.org/fhir/us/davinci-drug-formulary/StructureDefinition/usdf-Network-extension***|1.0.1***"
                        ]
                    }
                ],
                "mustSupport": true
            },

I think this is valid.
However, our ConstraintGenerator currently builds a constraint like this one for that:
extension('http://hl7.org/fhir/us/davinci-drug-formulary/StructureDefinition/usdf-Network-extension|1.0.1').count() >= 1

Based on the definition of the extension function, this is guaranteed to fail because FHIR extension URLs are not canonicals... i.e. should not include the |1.0.1 version suffix.

At the very least, we should strip the version suffix before generating constraints like this.
Event better would be to generate a constraint to test that a given usdf-Network-extension extension actual conformsTo this particular version of the extension (our current validation logic will only test it against the 'latest' extension definition with this URL).

Environment
Which version of IBM FHIR Server?

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Additional context
As an aside, I wish that extension URLs in instance data could be versioned.
I've mentioned that on chat.fhir.org a few times, most recently at https://chat.fhir.org/#narrow/stream/179166-implementers/topic/Extension.20with.20multiple.20versions/near/273818766
However, I've not actually submitted a tracker for it...pretty sure it would get rejected.

@lmsurpre lmsurpre added the bug Something isn't working label May 20, 2022
@lmsurpre lmsurpre self-assigned this May 22, 2022
lmsurpre added a commit that referenced this issue May 22, 2022
ConstraintGenerator.getProfiles() was called from 4 places in this
class.
All but one of those was for building the argument to the FHIRPath
`extension()` function.
That means that there should be no version suffix and so I renamed the
method to `getProfilesWithoutVersion` and updated it accordingly.

In the single other spot (`generateProfileConstraint(Node)`), I added
the `getProfile()` logic in-line.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 23, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 23, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 23, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 23, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
ConstraintGenerator.getProfiles() was called from 4 places in this
class.
All but one of those was for building the argument to the FHIRPath
`extension()` function.
That means that there should be no version suffix and so I renamed the
method to `getProfilesWithoutVersion` and updated it accordingly.

In the single other spot (`generateProfileConstraint(Node)`), I added
the `getProfile()` logic in-line.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
ConstraintGenerator.getProfiles() was called from 4 places in this
class.
All but one of those was for building the argument to the FHIRPath
`extension()` function.
That means that there should be no version suffix and so I renamed the
method to `getProfilesWithoutVersion` and updated it accordingly.

In the single other spot (`generateProfileConstraint(Node)`), I added
the `getProfile()` logic in-line.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
ConstraintGenerator.getProfiles() was called from 4 places in this
class.
All but one of those was for building the argument to the FHIRPath
`extension()` function.
That means that there should be no version suffix and so I renamed the
method to `getProfilesWithoutVersion` and updated it accordingly.

In the single other spot (`generateProfileConstraint(Node)`), I added
the `getProfile()` logic in-line.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
ConstraintGenerator.getProfiles() was called from 4 places in this
class.
All but one of those was for building the argument to the FHIRPath
`extension()` function.
That means that there should be no version suffix and so I renamed the
method to `getProfilesWithoutVersion` and updated it accordingly.

In the single other spot (`generateProfileConstraint(Node)`), I added
the `getProfile()` logic in-line.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
lmsurpre added a commit that referenced this issue May 24, 2022
1. Added a FHIRTermService.lookup overload which allows the caller to
pass the specific version of the CodeSystem to use. Previously, I found
that we were passing a CodeSystem to validateCode but this method
delegated to lookup which fetched its own CodeSystem. This was
problematic when the Coding didn't specify a particular CodeSystem
version when the underlying profile constraint did.

2. Moved logic for generating `conformsTo` constraints (generated-ext-1)
for each extension in the resource instance. Now it will be grouped with
the rest of the constraints and we can introspect those other
constraints to shape the constraint generation.
  - To implement this, I introduced a new "PathAwareCollectingVisitor"
although alternatively I could have executed a FHIRPath like
`descendents(extension)`
  - Instead of a constraint like `conformTo(url)` which will only
validate against the latest version of this extension in the registry,
we now generate an expression like `conformTo(url|1) or conformTo(url|2)
or conformTo(url|3)` ...one clause for each version in the registry.

Signed-off-by: Lee Surprenant <lmsurpre@us.ibm.com>
@lmsurpre
Copy link
Member Author

lmsurpre commented Sep 7, 2022

Went over an example with Robin and Prasanna and confirmed the generated constraint for a versioned extension reference includes the version in the conformsTo bit but not in the expression(<url>).count()

extension('http://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition/newpatients').exists() implies (extension('http://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition/newpatients').count() >= 1 and extension('http://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition/newpatients').all(conformsTo('http://hl7.org/fhir/us/davinci-pdex-plan-net/StructureDefinition/newpatients|1.0.0')))

@lmsurpre lmsurpre closed this as completed Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant