clinical_quality_language icon indicating copy to clipboard operation
clinical_quality_language copied to clipboard

DataRequirements test failures

Open Capt-Mac opened this issue 2 years ago • 8 comments

on the most recent release of cqfTooling while running ECQMCreatorIT tests two failures occured when verifying DataRequirements matched between bundle and measure:

TestCMS125FHIR StartMatOutputTest("CMS125FHIR-v0-0-004-FHIR-4-0-1.json", "BreastCancerScreeningsFHIR") failed on 'MedicationRequest' match

TestCMS816HIR StartMatOutputTest("HH-01FHIR-v0-0-010-FHIR-4-0-1.json", "HospitalHarmSevereHypoglycemiaFHIR") failed on "MedicationAdministration" match

currently the test has been commented out until bug on DataRequirements has been fixed.

Capt-Mac avatar Jan 26 '23 22:01 Capt-Mac

I am also seeing some unexpected behavior from the DataRequirementProcessor (currently using version 3.5.1). It would appear that something has changed between versions 3.1.0 and 3.2.0. If I use this small CQL file, I can replicate the behavior:

library "Test-Rule" version '0.0.1'
using FHIR version '4.0.0'
include FHIRHelpers version '4.0.0'
valueset "Test MedicationRequest VS": 'fake.medrequest.vs'
context Patient
define "Matching MedicationRequests": [MedicationRequest: "Test MedicationRequest VS"]

On version 3.1.0, the return value from gatherDataRequirements includes:

  1. a requirement for MedicationRequest containing a code filter for my value set
  2. a requirement for Patient

On version 3.2.0, repeating the same steps as above, I get:

  1. a requirement for MedicationRequest containing a code filter for my value set
  2. a requirement for MedicationRequest with no code filter attached
  3. a requirement for Medication with no code filter attached
  4. a requirement for Patient

The second and third requirements from version 3.2.0+ are unexpected to me. I tried up to version 3.6.0 and still see the same behavior from the DataRequirementProcessor.

It looks like this was the change which introduced the new behavior: https://github.com/cqframework/clinical_quality_language/pull/1228

amc514 avatar Feb 04 '24 08:02 amc514

Whats happening here is that Medication.medication is a choice type. It can be either a CodeableConcept or a Reference. In cases where it's a Reference, there's an implied requirement for Medication since you're referencing one directly by id.

The two other unfiltered data requirements fall out from that. Essentially, since you're referencing Medication by id but you don't know the ids ahead of time (it could whatever is stored in the medication Reference, you need all the Medications.

You can rewrite the last line as:

define "Matching MedicationRequests": ["MedicationRequest"] MR where MR.medication as CodeableConcept in "Test MedicationRequest VS"

And you'll see the behavior you're expecting.

JPercival avatar Feb 06 '24 21:02 JPercival

@JPercival the Medication.medication property is a reference in the case of our FHIR implementation. What I'm hoping to infer from the data requirements is that the Medication requirement is originating from this MedicationRequest requirement, such that I can add the _include=MedicationRequest:medication parameter to the MedicationRequest search request and not separately fetch all Medication resources.

I understand why it is logical to include some indication that this artifact depends on Medication due to the choice type of MedicationRequest.medication and the possibility of it being a reference, but is it possible to report it in such a way that it could be differentiated from an explicit dependency on the Medication resource from the CQL?

On the other hand, I don't understand why the MedicationRequest data requirement without a code filter is a logical data requirement for this artifact.

amc514 avatar Feb 06 '24 22:02 amc514

but is it possible to report it in such a way that it could be differentiated from an explicit dependency on the Medication resource from the CQL?

Based on my understanding of data requirements that's not how they are intended to be used. Rather, it's a way to share metadata about all possible data the CQL might access. This is useful for things like access-control. "User A can see MedicationRequests, but not Medications".

In this case, which particular Medications are read depend on the data stored within the MedicationRequests, which is not known ahead of time. The narrowest it could be scoped and still work for all cases is an unfiltered Medication.

On the other hand, I don't understand why the MedicationRequest data requirement without a code filter is a logical data requirement for this artifact.

The data requirements processor can see that some Medications will be filtered by a ValueSet (those that have a CodeableConcept for medication). But other Medications that have a reference can not be filtered by a ValueSet. It's unable to distinguish in this particular context that you only care about those with CodeableConcept, so it gives you an unfiltered Medication to ensure those that have a reference are also captured. The explicit as CodeableConcept in the example I gave you is the clue it needs to remove that additional unfiltered Medication. "I know I'm talking about medication, which may be a Reference or a CodeableConcept, but I explicitly only care about the ones with a CodeableConcept, which precludes Medications." It may be possible to enhance the inference there to doesn't add that additional unfiltered MedicationRequest. I'll have to look into that.

JPercival avatar Feb 06 '24 23:02 JPercival

Based on my understanding of data requirements that's not how they are intended to be used. Rather, it's a way to share metadata about all possible data the CQL might access. This is useful for things like access-control. "User A can see MedicationRequests, but not Medications".

This interpretation seems to conflict with the discussion here: https://cql.hl7.org/05-languagesemantics.html#artifact-data-requirements

It discusses in detail how to combine/collapse data requirements in order to produce "the minimum initial data requirements for the artifact, with any overlapping requests for the same type of data collapsed into a single request descriptor." Additionally, the presence of elements like codeFilter and dateFilter on the DataRequirement resource would indicate to me that they are meant to be used for optimal data fetching rather than primarily for access control.

The discussion in section 1.3 of the CQL Language Semantics guide is effectively exactly what we're trying to achieve, though we aren't bothering with the date filtering optimization at the moment, only the code filter so far. For this specific example of the MedicationRequest referencing a Medication, it'd seem the Includes component of the retrieve data requirement is most relevant. From that excerpt of the CQL guide:

Include elements for the clinical data. For data models that define relationships between data types, this element allows data matching the include relationships to be returned as part of the retrieve as well. Implementations that support this capability must ensure that included data returned is accessible via the related retrieve statements.

Though, I don't see a way to represent the include information in the FHIR resource for DataRequirement, so perhaps this is a gap with the resource definition? I'm far from a FHIR expert, though.

amc514 avatar Feb 07 '24 00:02 amc514

Based on my understanding of data requirements that's not how they are intended to be used.

This interpretation seems to conflict with the discussion here: https://cql.hl7.org/05-languagesemantics.html#artifact-data-requirements

It'd seem the Includes component of the retrieve data requirement is most relevant. From that excerpt of the CQL guide:

Though, I don't see a way to represent the include information in the FHIR resource for DataRequirement, so perhaps this is a gap with the resource definition? I'm far from a FHIR expert, though.

I'm referring to the FHIR data requirements returned by the DataRequirements processor in question, not artifact data requirements in the CQL spec. These are two separate and distinct specifications, despite the conceptual overlap and shared nomenclature. As you've pointed out, there's not a way to do includes in the FHIR data requirements.

with any overlapping requests for the same type of data collapsed into a single request descriptor

Currently with the CQL compiler you have to set collapseDataRequirements to true on the CqlCompilerOptions to opt-in to the collapsing behavior, though in this case it would not help.

JPercival avatar Feb 07 '24 02:02 JPercival

These are two separate and distinct specifications, despite the conceptual overlap and shared nomenclature.

I see, thank you for clearing up that source of confusion!

If we take the DataRequirementProcessor and FHIR out of the question, is it currently possible to implement the logic described in the CQL spec I referenced above? We're using the cql2elm package to compile our CQL, which to my understanding utilizes the Cql2ElmVisitor class that was updated in #1228. Is that also going to prevent us from accurately analyzing and collapsing the ELM data requirements as described in the CQL spec?

amc514 avatar Feb 07 '24 04:02 amc514

Yes, the logic for that analysis is partially implemented internally and is the source for the FHIR data requirements. Here's the package for that. In particular the ElmRequirementsVisitor may be of interest to you:

https://github.com/cqframework/clinical_quality_language/blob/master/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/

We've yet to come up with a public API or serialization format for the ELM requirements, and includes have yet to be implemented, but you may find something useful there. We're definitely interested in support includes here it just hasn't bubbled up the backlog yet.

JPercival avatar Feb 07 '24 15:02 JPercival