Referring to the enclosing composition from ACTION.instruction_details?

Hi,
My name is Ann-Sofie and I’m working at the Karolinska University Hospital in Stockholm.

We’re trying to understand how to best populate references to the enclosing composition, when referring from an action to an (activity within an) instruction in the same composition.

The use case is to refer to each related medication order, from each medication management, in a structure like the below to set the ACTIVITY in a planned or scheduled state:

What we’ve learned so far, from the specifications and with some help from @ian.mcnicoll, is that we should use the ACTION.instruction_details attribute for this, which means we would like to produce something like the following in canonical format:

or possibly, if the full composition uid should be used:

and in flat format:


or

To create compositions with instructions_details like the above, when the instruction is in the same composition as the action, we need a way to

  • either explicitly set the composition uid in the create request, and also refer to that uid in the instruction_details (in the same create request payload),

  • or a way to implicitly refer to the enclosing composition (and let the EHR server create the uid).

Betters CDR (EHR Server) has a convenient special value, $selfComposition, that can be used to refer to the enclosing composition, and which will be replaced with the actual generated uid when the composition is created. This works both in canonical and flat format. So if we provide the following in the create composition payload to Betters CDR:


the CDR will replace the $selfComposition value with the generated composition uid, i.e. resulting in:

So, what we are wondering is:

  1. Is there any alternative way to implicitly refer to the enclosing composition, that may work in more CDRs than Betters? Or are there plans to incorporate the Better $selfComposition reference value or something similar in the specifications? Should we create a specification Problem Report?

  2. If we would go with the option of explicitly setting the composition uid when creating the composition, what is the latest recommendation for doing that? (For canonical and flat, respectively, if different) It seems the question was left somewhat open in the following discussion thread :
    REST API for creating compositions with id (started by @Dileep_V_S )
    and related ticket:
    [SPECITS-62] - openEHR JIRA (reported by @sebastian.iancu )

  3. Is there a recommendation (or even specified in the specs?) for whether to use the full composition uid or only the uuid/guid part, in the instruction_details|composition_uid (i.e. /instruction_details/instruction_id/id/value)?
    From the spec it seems to me that only the uuid/guid part should be used, e.g. from https://specifications.openehr.org/releases/RM/latest/common.html#_unique_node_identification:
    ” …top-level types such as COMPOSITION, EHR_STATUS, PARTY etc for which it is recommended to set the uid value to a copy of the uid.object_id() value of the owning VERSION object (usually an ORIGINAL_VERSION), i.e. the leading Uid, which is normally a Guid. This enables easy identification of standalone top-level objects in a serialised form. For example, if the ORIGINAL_VERSION.uid is 87284370-2D4B-4e3d-A3F3-F303D2F4F34B::uk.nhs.ehr1::2, the Guid 87284370-2D4B-4e3d-A3F3-F303D2F4F34B would be copied to the contained COMPOSITION.uid field.”
    Also, in examples in both the Better developer guide (https://docs.better.care/ehr-server/3.2/web_templates/web_templates_developer_guide.html#_linking_instructions_and_actions) and the EHRBase docs (e.g. here: 8.2. RM-Mappings — EHRbase documentation) only the leading Guid part is specified, e.g.:


    On the other hand, we have also seen examples where the full composition uid is used, and that is also what is generated by the Better CDR (EHR Server) when using the $selfComposition value in the create request – i.e. providing the following in the create payload:

    will result in a composition_uid populated like this:

3 Likes

Hi,

From my own experience similar with the above mentioned, I can tell that we were not saving actions in the same composition as the instruction, as that will lead in time to a huge composition and to a lot of unnecessary composition-updates of something that is actually fixed (INTRUCTION/ACTIVITY); we usually save INTRUCTION into a separate composition then the ACTIONs.
Thus, referring to a predefined (already persisted) INTRUCTION in the ACTION is much easier, that uid is already allocated, no need for any of the above mentioned $selfComposition or the SPECITS-62.

Also, about your point 3.) above, we mostly use the Guid of the composition, which in semantic terms it means the latest variant of a particular INTRUCTION.
In some situations (depends on use-case) you might want to refer to a particular snapshot point-in-time composition, then you use for example that 87284370-2D4B-4e3d-A3F3-F303D2F4F34B::uk.nhs.ehr1::2. In this sense, what Better sets it correctly, but the question is if that is fulfilling your use-case.
But if you store the ACTIONs with the INSTRUCTION, then I think pointing to an exact version sounds the right thing to do.

2 Likes

Regarding this particular example, in this case we were thinking to create the INSTRUCTION+ACTIVITY plus its initial status (“scheduled”) in the same composition, since these effectively happen “at the same time” in the actual healthcare process of this case, and then all subsequent updates (ACTIONS to the same INSTRUCTION+ACTIVITY with other status) will come in new (separate) compositions.

By always ensuring that we create an initial ACTION for every ACTIVITY, then we can try to standardize how we will query/evaluate the status: there will always be at least one ACTION for the Activity, and we should always just read the latest one to get the current status, no matter what (even if the latest one is still just this initial “Created/Scheduled” kind of status).

To create this initial “Created/Scheduled” status ACTION in the same composition vs a separate composition felt a bit like a question of taste/preference, but we were thinking to put it in the same initial composition just to make it easier for the creation process, and give the whole thing a nice “packaged” feel… but of course, open for feedback!

Having said all of that I do feel that the 2 main questions posed by @Ann-Sofie.Stolperud are very relevant:

  1. should the composition_uid given for a specific instruction_details be the fully versioned object ID or just the UUID itself (so that “latest” version of that UUID should always be assumed)
  2. how should one set the composition_uid when creating ACTIONS in the same composition? In some (but not all) implementations there are special variables/expressions that take care of this resolution for you (very nice!) but it feels like it would be much better if this were standardized

Regarding “what the composition_uid should look like,” I personally feel that this depends on how this will be read when later trying to query/evaluate the current / latest state, so IMO that is maybe an even bigger question. From my perspective, that is the key question I would also like to add here :slight_smile:

I feel that the design of this is explained quite well in the specification (see EHR Information Model specification sections 8.2.5.5, 8.2.5.6, and 8.2.5.7 ) but that the implementation of how to acheive/execute this kind of logic does not seem to exist anywhere in the specification??

And again here in some (but not all) implementations we have seen the addition of custom functions you can execute in AQL to get the current state of a given ACTIVITY or even the aggregate state of all activities within an INSTRUCTION but this is not part of the specification either. IMO it is here that the format of the various linking identifiers really matters (full object id with version suffix vs just the UUID without the version suffix, for example).

I can see how you might be able to “roll your own” and write an AQL expression to fetch the status in a “semi” generic way, but it feels like you will potentially need to recreate this kind of logic over and over again; it would be nice if there was a more standardized/non-proprietary/non-custom-AQL-query-every-time way to fetch the current/latest state of ACTIVITIES and INSTRUCTIONS based on how the design of these relationships is specified per the above-linked EHR Information Model sections. Perhaps within this is where the nuances between specific version vs “latest” could be taken care of, as well (or at least explained a bit more so the ramifications are clear)?

2 Likes

Sorry for a brief reply but I’m on vacation. @vidi42 may be able to advise if ehrbase supports the selfComposition construct. If not, it might be possible to use a /contribution call with a preallocated composition uid. Contributions allow multiple compositions to be submitted at the same time. Im not a position to test this though!

As far as I know EHRbase doesn’t have the selfComposition placeholder support. However, following the discussion in REST API for creating compositions with id, we changed so EHRbase respects the provided composition uid during create, so this should allow you to reference the same id somewhere else in the composition. This works regardless of the format you use, JSON, FLAT.

1 Like

Hi and thanks for following up on this @vidi42 !
I was actually just trying this over the last few days with both 2.6.0 and the current “next” version and found that it does seem to work well with your “ecis” endpoint (Flat/Structured) but does not seem to work with the openEHR endpoint (using canonical JSON or XML).

Here is what I see when trying to do a POST of a new Composition where I have set the UID:

POST /ehrbase/rest/openehr/v1/ehr/{ehr_id}/composition
...
  "archetype_node_id" : "openEHR-EHR-COMPOSITION.prescription.v0",
  "uid" : {
    "_type" : "HIER_OBJECT_ID",
    "value" : "0794e68d-5003-4a19-9b65-28fc7dfa6e35::local.ehrbase.org::1"
  }
}

HTTP/1.1 412 Precondition Failed
{"error":"Precondition Failed","message":"Provided Id 0794e68d-5003-4a19-9b65-28fc7dfa6e35::local.ehrbase.org::1 is not a ObjectVersionId"}

I have tried also with using PUT but once getting the If-Match set up properly then I always just get a 404 response (I am assuming since the Composition I am trying to PUT in the URL does not already exist…).

Is there a different format or value that is expected when using canonical format? Or if this is not the desired behavior then I can create an issue on your Github repository; either way is fine for me!

Until then we are working towards moving some of our stuff over to use Flat just to handle this case (where we had been using canonical JSON before).

Ah, the error message might be a bit misleading, because you did provide an ObjectVersionId value, but the _type is wrong. The openEHR endpoint only works with OBJECT_VERSION_ID, so you would need to change to the following:

POST /ehrbase/rest/openehr/v1/ehr/{ehr_id}/composition
...
  "archetype_node_id" : "openEHR-EHR-COMPOSITION.prescription.v0",
  "uid" : {
    "_type" : "OBJECT_VERSION_ID",
    "value" : "0794e68d-5003-4a19-9b65-28fc7dfa6e35::local.ehrbase.org::1"
  }
}

Please let me know if it works.

2 Likes

Thanks @vidi42 , glad that you pointed this out!
We are actually not going directly from a composition as text to the openEHR API, but we are instead using your openEHR_SDK for helping take care of some stuff before. It works like this:

  1. composition in Flat JSON text gets unmarshalled to an instance of com.nedap.archie.rm.composition.Composition using openEHR_SDK’s FlatJasonProvider.buildFlatJson().unmarshal()
  2. we “do stuff” to the Composition (e.g. fix up some FeederAudit stuff, validations, etc)
  3. composition gets marshalled back to text in whatever format we want (RMDataFormat.marshall())
  4. then the result will be actually POSTed to the API

So the problem there was that we also needed to update the version of the openEHR_SDK we were using for all of this to take in the change that also came with EHRbase 2.6.0 :wink: (so I bumped it to 2.16.0). Now it comes out correctly with OBJECT_VERSION_ID

However, one thing I noticed and thought weird was that the composition_uid getting set under .../_instruction_details|composition_uid of an ACTION was then coming out as a HIER_OBJECT_ID LOCATABLE_REF id within that ACTIONs instruction_details (when you read the composition out as canonical JSON after creating it, I mean). My assumption would be that this should also be an OBJECT_VERSION_ID since it is the exact same value that is being set on the composition uid (the full string including system and version number), but… what EHRbase is doing here matches exactly what we see with Better’s, so maybe it is fine? Or is this potentially an issue?

And then with ALLLLL of that said, my proposal to our team has been that we stick with using Flat anyway, we use the same variable/expression $selfComposition, but in the case when we are writing this to EHRbase then we will run the composition first though a sort of “pre-processor” that will take care of determining the right full composition version string (if it is a brand new composition vs an update to an existing where we need to just increment the version number), and then swap all instances of the expression $selfComposition with this real value before actually posting it to the API.

A little bit of a “trick” but in the end it means we can use our solution with multiple different vendor implementations and just turn on or off this “pre-processor” part depending on which vendor’s API we will be using for that case.

Even nicer will be if/when things like this could become standardized and we did not need these kind of flags/variants for different implementations :nerd_face:

4 Likes

Hi again,

Last week I created an issue on EHRbase’s repo that is related to this: Get linked ACTIONs and latest state for INSTRUCTIONs/ACTIVITYs · Issue #1386 · ehrbase/ehrbase · GitHub

Basically with EHRbase up to v2.6.0 it is not possible to directly fetch or filter anything under an ACTIONs instruction_details using AQL (you get HTTP 400 with “Not implemented” as a response) so it does not seem easily possible to get an Instruction/Activity’s current state with EHRbase unless you 1) execute multiple different queries and then perform some kind of matching operation to get only the ones that should then be matched together or 2) use something else in the composition to match on (e.g. add some identifiers to the template and then populate them just for the purpose of matching our Actions to their Activities in AQL?).

But in my mind it goes back to some of the original questions in this thread, and thus the following 4 “gaps” (or at least “unclear things”?) that do not seem to exist anywhere in the specification that create challenges when trying to use and link INSTRUCTION + ACTIVITY + ACTIONs in practice:

  1. Standardized (exists in the specification somehow?) ability to create a composition with a UID determined by the client (POST or PUT? with a client-specified composition/_uid) - works with EHRbase, but not others?
  2. Some kind of standard (again, exists in the specification somehow?) “helper variable” when needing to refer back to the same composition as it is created/updated - Better EHR Server has $selfComposition that can be used but does not exist in EHRbase and unclear if any other implementation has similar?
  3. Standardized (again, exists in the specification somehow?) way to retrieve current state of a given Activity and aggregate state of a given Instruction based on all of the possible linked actions - Better EHR Server has some help functions you can use in AQL for this such as current_state, instruction_aggregate_state, etc but not aware of any similar solution from other implementation?
  4. Standardized (in the specification… ?) format for what should actually be saved in the different fields that exist under an ACTIONs instruction_details, specifically for things like composition_uid and if it should be with or without version and/or any other anomalies that can exist here? And namely so that it works correctly with whatever solution would exist from # 3 above - Better’s solution and above functions seems to work “out of the box” with full version-based IDs but again as there does not seem to be any other standard functions then it is unclear how this would be interpreted by any other implementation?

I am not really sure how to take this further but it feels like it needs a bit of a broader engagement if it is something which should include some design decisions and additions/changes to the actual specification(s)?

3 Likes

Thanks Joshua,

I’d be happy to ask for these items to be put on the agenda of the next Specification Group meeting.

@sebastian.iancu @Bostjan_Lah @rong.chen

4 Likes

During the SEC meeting today we decided that the SEC REST (sub)workgroup gets the task to clarify the specification regarding that client supplied UIDs should be used (not changed) by the recieving server including:

  • what errors should be thrown if ID collisions etc. are detected
  • if POST or PUT should be used for client supplied IDs (as discussed in e.g. [SPECITS-62] - openEHR JIRA )

We did not have time during the SEC to discuss if the reference in INSTRUCTION_DETAILS.instruction_id should/could point to a specific version of a COMPOSITION or not - but that would also need to be better described and exemplified in the specifications.

The approach with $selfComposition was not considered to be a prefered solution. Instead proper client-selected IDs was preferred since that would solve more other use cases at the same time than $selfComposition would.

Since there is no AQL sub-working group, the question regarding standardisation of AQL convenience functions such as current_state and instruction_aggregate_state will remain with the main SEC for some later point in time (it would be good to create a problem report and/or change request to track this issue if none already exists).

3 Likes

In a SEC-meeeting now @pablo noted that The issue SPECPR-221 might also be good to look at when thinking about this.