One topic that comes up fairly often when I talk procurers and users of interoperability is ‘clinical safety’. Everyone knows why it’s important, but it’s much harder to pin down what it is, and how to measure it, or how to ‘be safe’. With this in mind, the FHIR specification includes an implementer safety checklist. All developers implementing FHIR should run through the content of this safety checklist before and after the implementation process. But the lack of feedback I get about it suggests to me that not many people read it.
With this in mind, I’ll be asking participants in this weekend’s connectathon in Orlando to fill it out. I’m sure we’ll get comments from that. Here’s the safety checklist, with my comments, but first:
Almost all interoperability developments occur in a limited context with one to a few trading partners, and relatively well controlled requirements. In this context, safety consists of testing the known functionality, but all too often, ignoring all the other things that might happen. However experience shows that over time, new participants and new requirements will creep into the ecosystem and safety features that appeared unnecessary in a well controlled system turn out to be necessary after all. These safety checks below are mostly chores, and are easily ignored, but a warning: you ignore them at your peril (actually, it’s worse than that- you ignore them at other people’s peril).
Production exchange of patient or other sensitive data will always use some form of encryption on the wire.
This is a fairly obvious thing to say in principle, but it’s extremely common to find insecure exchange of healthcare data in practice. FHIR does not mandate that all exchange is encrypted, though many implementers have commented that it should. There are some valid use cases not to use encryption, such as terminology distribution etc. Implementers should check that their systems are secure.
For each resource that my system handles, I’ve reviewed the Modifier elements.
In resource definitions, a number of elements are marked as modifying elements. Implementers are not required to support these elements in any meaningful fashion. Instead, implementers are required to ensure that their systems do not inappropriately ignore any of the possible values of the modifier elements. This may be achieved by:
- Ensuring that these values will never occur through proper use of the system (e.g. documenting that the system only handles human patients)
- Throwing an exception if an unsupported value is received
- Ignoring the element that contains the modifier element (so that the value is irrelevant anyway)
Note that applications that store and echo or forward resources are not ‘processing the resources’. Processing the resources means extracting data from them for display, conversion to some other format, or some form of automated processing.
My system checks for modifierExtension elements.
Modifier Extensions are only seen rarely, but when they exist, they mean that an implementer has extended an element with something that changes the meaning of the element, and it’s not safe to ignore the extension. For safety purposes, implementers should routinely add some kind of code instruction like this:
Assert(object.hasNoModifiers, “Object at path %p has Unknown modifier extensions”)
This should be done for each object processed. Of course, the exact manifestation of this instruction will vary depending on the language. Performing these checks is a chore, so it’s frequently not done, but it should be done for safety purposes. Note that one cheap way to achieve this is to write a statement in the documentation of the application: “Do not send this application any modifier extensions”. Like all cheap ways, this is likely to not be as effective as actually automating the check.
My system supports elements labelled as “must-support” in the profiles that apply to my system.
Implementation Guides are able to mark particular elements as ‘must-support’. This means that although the element is optional, an application must be able to populate or read the element correctly. What precisely it means to do this correctly varies widely, so Implementation Guides must indicate exactly what they mean when marking an element as ‘must-support’, and applications that claim to conform need to do whatever is prescribed.
For each resource that my system handles, my system handles the full Life cycle (status codes, record currency issues, and erroneous entry status). Many resources have a life cycle tied to some business process. Applications are not required to implement the full business life cycle – they should implement what is needed. But systems need to fail explicitly if the life cycle they expect does not match the content of the resources they are receiving
A common and important area where applications fail to interoperate correctly is when records are created in error, or linked to the wrong context, and then must be retracted. For instance, when a diagnostic report is sent to an EHR linked to the wrong patient. There are a variety of ways to handle this, with different implications for the record keeping outcomes. Failure to get this right is a well-known area of clinical safety failure.
The FHIR specification makes some rules around how erroneous entry of resources is indicated. Applications should ensure that they handle these correctly.
My system can render narratives properly (where they are used).
The general theory of text vs data is discussed here and here. Resources can contain text, data or both. Systems are not obliged to be able to display the narrative; they can always choose to process the data. But in many cases, it’s a good idea to offer the user a choice to see the original narrative of the resource (or resources, in many cases), particularly for clinical resources. This might be described as ‘see original document’ in a user relevant language.
The FHIR specification makes no explicit requirements in this regard, since the correct behaviour is so variable. Implementers should judge for themselves what is appropriate in this regard.
My system has documented how distributed resource identification works in its relevant contexts of use, and where (and why) contained resources are used.
Many of the clinical safety issues that arise in practice arise from misalignment between systems around how identification and identifiers work. In the FHIR context, this risk is particularly acute given how easy it is to develop interfaces and connect systems together. Any applications that assign identifiers or create resources with an explicit identity should document their assumptions and processes around this. This is particularly important where there is the prospect of more than two trading partners.
The same applies to contained resources: a system should refrain from using contained resources as much as possible, and where it necessary, document the usage.
My system manages lists of current resources correctly.
One important use of the List resource is for tracking ‘current’ lists (e.g. Current problem list). Current lists present a challenge for the FHIR API, because there’s no inherent property of the list that marks it as ‘current’: there may be many ‘medication lists’ in an application, but only a few(or one) of them are the ‘current’ list. What makes a list current is it’s context, how it used, not an inherent property of the list. The FHIR API defines an operation that can be used to get a current list for a patient:
The FHIR specification defines several list tokens for use with this operation but there’s a long way to go before these concepts are well understood and exchangeable. If the system has current lists, it must be clear how to get the correct current list from the system and how to tell the lists that are not.
My system makes the right Provenance statements and AuditEvent logs, and uses the right security labels where appropriate.
Provenance and AuditTrail are two important and related resources that play key roles in tracking data integrity. Provenance is a statement made by the initiator of an update to the data providing details about the data change action and AuditTrail is a statement made by the data custodian about a change made to the data. On a RESTful API, the provenance statement is made by the client, and the AuditTrail is created by the Server. In other contexts, the relationships may not be so simple
My system checks that the right Patient consent has been granted (where applicable).
Patient consent requirements vary around the world. FHIR includes the ability to track and exchange patient consent explicitly, which is a relatively new integration capability. Various jurisdictions are still feeling out how to exchange consent to meet legislative and cultural requirements.
When other systems return http errors from the RESTful API and Operations (perhaps using Operation Outcome), my system checks for them and handles them appropriately.
Ignoring errors, or not handling them properly, is a common operational problem when integrating systems. FHIR implementers should audit their system explicitly to be sure that the http status code is always checked, and errors in OperationOutcomes are handled correctly
My system publishes a conformance statement with StructureDefinitions, ValueSets, and OperationDefinitions, etc., so other implementers know how the system functions.
While servers have no choice but to publish a conformance statement, the degree of detail is up to the implementer. The more detail published, the easier it will be for systems to integrate. Clients should also publish conformance statements too, but there is much less focus on this – but the computable definition of system functionality will be just as important.
My system produces valid resources.
It is common to encounter production systems that generate invalid v2 messages or CDA documents. All sorts of invalid content can be encountered, including invalid syntax due to not escaping properly, wrong codes, and disagreement between narrative and data.
In the FHIR ecosystem, some public servers scrupulously validate all resources, while others do not. It’s common to hear implementers announce at connectathon that their implementation is complete, because it works against a non-validating server, and not worry about the fact it doesn’t work against the validating servers.
Use the validation services to check that your resources really are valid, and make sure that you use a DOM (document object model) or are very careful to escape all your strings
Check for implicitRules.
All resources can carry an implicitRules pointer. While this is discouraged, there are cases where it is needed. If a resource has an implicitRules reference, you must refuse to process it unless you know the reference. Remember to check for this.