-
Notifications
You must be signed in to change notification settings - Fork 1
Pathways on FHIR
This page serves as documentation of our approach to representing oncology clinical pathways with mCODE, using the Clinical Practice Guidelines Implementation Guide (CPG IG) and related FHIR Clinical Reasoning resources
The fundamental goal of this project is to bring the mCODE data standard into the world of oncology clinical pathways. Camino is a mature prototype intended to demonstrate the art of the possible with mCODE - automatically reading a patient's record and applying a pathway to see what's already been completed, and highlight the next recommendation for action from the user. But Camino's data model is not a standard - it's a very simple JSON structure, inspired heavily by Synthea's generic modules, and designed purely to support the features of the prototype. In order to drive true interoperability we need to work within existing standards where possible.
(Put a brief summary of the CPG IG and FHIR clinical reasoning module here. Copious links encouraged)
Note: the hierarchy of profiles within the CPG IG is Shareable < Computable < Shareable < Executable. We should always aim to implement the highest level (i.e., Executable) whenever possible, unless there is a compelling reason not to.
We want to support two basic paradigms for pathway creation:
- Small, modularized pathways, which represent a single phase of "action" and can be linked together in various ways
- Large, longitudinal pathways, which represent an entire sequence of care for a patient's cancer
These can both be created using two basic concepts:
- "actions", where a clinical activity, such as a prescription, procedure, or chemo regimen may be requested
- "branches", where some aspect of the patient or their condition drives the path of care in one of multiple directions
Because the FHIR resources depend on boolean-valued expressions as well as allow for more complex logic to drive dynamic values, there are multiple approaches that pathways could be represented using FHIR and CQL.
One extreme is to include all branching and evaluation logic within the CQL itself, and the FHIR only represents a single action of "do whatever the CQL says to do next". That's generally against the spirit of the CPG data model though, and probably not easy to maintain either. The ideal approach would logically split out the FHIR and CQL to leverage each one's strengths.
The central resource in all of this is the PlanDefinition
, with ActivityDefinition
, Library
, and CarePlan
resources also involved.
Name | Description |
---|---|
CPGPublishablePathwayDefinition |
... |
CPGPathwayDefinition |
... |
CPGStrategyDefinition |
... |
CPGRecommendationDefinition |
... |
The ActivityDefinition
resources represent the detailed definition of "actions" as described above. If an activity is determined to be applicable, then the code
and/or product[x]
fields will be used to populate a corresponding Request resource.
The CarePlan
resource is the result of applying a Patient resource against a PlanDefinition.
cqf-ruler "is an implementation of FHIR's Clinical Reasoning Module and serves as a knowledge artifact repository and clinical decision support service." In practical terms, cqf-ruler is the only* FHIR server that will allow us to use the PlanDefinition$apply operation with a Patient and get back a CarePlan resource with appropriate actions.
( * = the IBM FHIR server may also support some of what we want to do based on this discussion and linked PR, but the docker image doesn't seem to work out of the box)
The implementation of the PlanDefinition$apply operation is here: https://github.com/DBCG/cqf-ruler/blob/master/r4/src/main/java/org/opencds/cqf/r4/providers/PlanDefinitionApplyProvider.java and the implementation of ActivityDefinition$apply, which PlanDefinition$apply calls for each action, is here: https://github.com/DBCG/cqf-ruler/blob/master/r4/src/main/java/org/opencds/cqf/r4/providers/ActivityDefinitionApplyProvider.java
The basic flow of PlanDefinition$apply
is as follows:
- for each
action
in PlanDefinition:- if all "applicability" conditions with type "text/cql" in
condition
are met:- note it only appears to support CQL, not ELM
- note that nested sub-actions are evaluated, presumably to for exceptions, but their applicability is not used anywhere, nor are nested sub-actions ever "applied"
- find the referenced ActivityDefinition from
definitionCanonical
- note: the spec allows this to be a PlanDefinition, but only ActivityDefinitions are currently supported
- call
ActivityDefinition$apply
:- note at this point the ActivityDefinition is completely standalone, it has no link back to the PlanDefinition
- depending on
kind
, one of the following resource types will be populated:- ServiceRequest
- requires
code
ordynamicValue
-
dosage
andproduct
not allowed
- requires
- MedicationRequest
- requires
product
-
bodySite
,code
, andquantity
not allowed
- requires
- SupplyRequest
- Procedure*
- DiagnosticReport*
- Communication*
- CommunicationRequest
- sets
ActivityDefinition.code.text
asCommunicationRequest.payload.content
- sets
- ( * = not actually allowed by the spec? see https://www.hl7.org/fhir/activitydefinition-definitions.html#ActivityDefinition.kind)
- note: the FHIR spec allows additional types, noted below, but the above are the only types supported in cqf-ruler
- Appointment
- AppointmentResponse
- CarePlan
- Claim
- Contract
- DeviceRequest
- EnrollmentRequest
- ImmunizationRecommendation
- NutritionOrder
- Task
- VisionPrescription
- ServiceRequest
- apply any
dynamicValue
s from the ActivityDefinition, if any, to the activity result - return the activity result
- apply any
dynamicValue
s from the PlanDefinition.action, if any, to the result - note it does not use any other fields on PlanDefinition.action, such as
relatedAction
,trigger
,input
/'output`, etc...
- if all "applicability" conditions with type "text/cql" in
There is also a resolveCdsHooksPlanDefinition
function, which is never actually directly called in the code that I can see, and it has the comment "For library use". At a glance it seems much more robust, and this comment on an issue in the repo confirms that: https://github.com/DBCG/cqf-ruler/issues/45#issuecomment-389242647