A weekly summary of chat.fhir.org to help you stay up to date on important discussions in the FHIR world.
Hi all! Could you help me to understand some use cases of Smart on FHIR (v1)?
I have a FHIR Server on [base-url]
and an Authorization Server on [auth-server]
. And a user has an access to couple of Patients resources and their clinical data (pt-1 & pt-2).
1) Let's suppose that the user provided a grant to 3rd party app within next scope 'patient/Patient.read patient/Observation.read patient/Observation.write' and patient=pt-1 in context. As a 3rd party, what responses should I expect?
GET [base-url]/Patient/pt-1
GET [base-url]/Observation?subject=pt-1
GET [base-url]/Patient/pt-1/Observation
GET [base-url]/Patient
GET [base-url]/Patient/pt-2
GET [base-url]/Observation?subject=pt-2
GET [base-url]/Observation?subject=pt-3
GET [base-url]/Observation
POST [base-url]/Observation
subject:
reference: Patient/pt-2
I believe that the first three requests should return 200 OK + data, and the rest of them 403 Unauthorized. Right? Or it depends on something?
2) Let's say we have not Observation, but CommunicationRequest resource. Which are search parameters available for 3rd party app within patient/CommunicationRequest.read scope? subject, sender, recipient, requester?
3) I'm thinking of building a tenant-based FHIR API which uses user-id as url prefix for every request.
[base-url]/user/<user-id>/Patient/pt-1 => 200 OK
[base-url]/user/<user-id>/Patient/pt-2 => 200 OK
[base-url]/user/<user-id>/Patient/pt-3 => 404 Not Found
I would say I have a lot of logical FHIR Servers on top of physical one. In case of EHR launch I could provide different iss parameters depending on the user who launched the app, so it could help me simplify access control module.
But I can't find an answer if it's possible to make something similar in case of Standalone launch. It seems like 3rd party app should know the only base-url and use it for every user? Is it possible to subsistute [base-url] somehow while launching?
For (1): in our server they are all 200 OK, they just return only the data of pt-2, so GET [base-url]/Observation?subject=pt-2 returns an empty bundle
(2) Which search parameter are available is unrelated to the scopes
(3) Don't think that would work, clients expect a fixed URL to connect to
(1.1) We have the same solution for now, but I'm not sure if it's correct using Authorization header as an implicit parameter for business logic. Will my server be conformant with FHIR Specification (which is RESTful) if it provides different responses on the same url depending on Authorization header? I believe, that according to REST, the role of Access Conrol is only accept/reject requests, but not influence on the result. So, I would say that in this case our FHIR Servers are not conformant with FHIR Specification. Is it correct, or I miss something?
(1.2) And what about saving resources (POST/PUT/PATCH)? Should my FHIR Server set reference to the patient implicitly or validate and require correct reference value in the body?
(2) From the smart app developer point of view, how should I understand which endpoints (or/and search parameters) are available within a specific scope I got from user? Does specification have this answer, or I have to adopt my application to every specific FHIR Server?
(3) I feel that the specification tries to connect Smart App Developer and FHIR Server Developer and it provides a concrete authentication flow. But as a Smart App dev, once I have a token, I don't see my capability within my scopes. And as FHIR Server dev I don't see a standard way to provide such capabilities.
So, once FHIR Server provided 'patient/Patient.read patient/Observation.*' scope, does it obligated to accept requests to [base-url]/Patient/<pt-id>, [base-url]/Observation
, etc?
Will my server be conformant with FHIR if I just say in documentation, that within patient/...
scopes smart app should use another base-url. e.g. [base-url]/patient/<pt-id>
([base-url]/patient/«pt-id>/Patient/<pt-id>, [base-url]/patient/<pt-id>/Observation
).
policies are important. principles of REST do not override policies.
In general with smart, it is okay for a server to reject a query prospectively/statically because of scopes. It is also okay for a server too simply redact results because of scopes. We don't have prescriptive behavior on this. The only thing it's not okay to do is return data beyond what the scopes allow.
The question of what endpoints are available is somewhat orthogonal to your scopes. For example, a server might advertise in its documentation or in its capability statement that it supports a "batch" endpoint; if it does, clients can call this end point with requests that are consistent with the available scopes. If it does not, clients can't.
I wonder SMART on FHIR based on baseUrl convention instead of more flexible HATEOAS. Why server after auth could not just return explicit baseUrl for the client with access_token ?
{
access_token: ....
fhirBaseUrl: ....
}
Compartments like /Patient/<id>/{metadata,Observation,Encounter} look like good fit for SMART Clients and Servers.
Thank you! I do missed that part in Access Denied Response Handling chapter.
Just to clarify, if I have a FHIR Server which is rich on capability, it is ok to restrict some access depending on client type, not only scopes provided to that client, isn't it?
That would work for areas like the patient compartment where fhir explicitly defines some context, but the mapping breaks down pretty quickly too. For example even with "patient" compartments, a smart app authorized to access data about a given patient might be able to see certain data outside of a compartment, such as data directly linked from or needed to interpret the data in the compartment. So passing the patient id (or fhirContext[] as array of references as proposed in SMARTv2) has been a flexible choice.
Michele Mottini said:
For (1): in our server they are all 200 OK, they just return only the data of pt-2, so GET [base-url]/Observation?subject=pt-2 returns an empty bundle
Should not server respond with 403 for (1)?
Josh Mandel said:
That would work for areas like the patient compartment where fhir explicitly defines some context, but the mapping breaks down pretty quickly too. For example even with "patient" compartments, a smart app authorized to access data about a given patient might be able to see certain data outside of a compartment, such as data directly linked from or needed to interpret the data in the compartment. So passing the patient id (or fhirContext[] as array of references as proposed in SMARTv2) has been a flexible choice.
What is fhirContext?
We are thinking about "poko yoko" for Smart on FHIR apps - i.e. implicitly inject patient id into all search and even CRUD operations.
@Josh Mandel what is your opinion about such an implicit server behavior?
nicola (RIO/SS): Michele Mottini said:
For (1): in our server they are all 200 OK, they just return only the data of pt-2, so GET [base-url]/Observation?subject=pt-2 returns an empty bundle
Should not server respond with 403 for (1)?
From the SMART spec perspective, both of these are OK behaviors.
What is fhirContext?
See FHIR-32253; this is being added to resolve SMARTv2 ballot feedback
nicola (RIO/SS): We are thinking about "poko yoko" for Smart on FHIR apps - i.e. implicitly inject patient id into all search and even CRUD operations.
I like this, but there are edge cases where it'll prevent access that a client should have (e.g., with patient/*.cruds
access, you might still be allowed to issue a query like GET /Observation/123
where the subject of the observation is something other than the patient (say, a patient's device or location).
Michele Mottini said:
For (1): in our server they are all 200 OK, they just return only the data of pt-2, so GET [base-url]/Observation?subject=pt-2 returns an empty bundle
I think for (1) - 403 is more honest - otherwise, the client may be confused and interpret the empty response as a lack of data
I think no error is better. Using 403 is actually _leaking_ the information that there is data that the client cannot see
Yep, if they're fishing for information, a 200 tells them nothing, a 403 says there's data which is a problem from a privacy point of view
AND this is why the actual value returned should be driven by POLICY. http://hl7.org/fhir/security.html#AccessDenied
i’m reviewing smart on FHIR (EHR launch) implementation (based on oauth 2.0 authorization code flow) where the EHR launches the application calling a launch URL specified in EHR configuration. The launch url contains a launch token in the query parameter and then the application exchanges the launch token along with the client identification parameter to get an authorization code and eventually access token from the authorization server.
My concern is that an attacker can steal or copy a valid launch token which hasn’t been used before and get an authorization code from the EHR authorization server, this is because the server cannot determine if the entity redeeming the launch token is the same user for whom the token was originally generated. There is no mechanism for the server to verify the identity of the redeemer and ensure only the right user receives the authorization code. Is this a valid threat or am I missing something?
For reference, Epic’s implementation is based on SMART on FHIR, an industry standard through HL7, link- https://fhir.epic.com/Documentation?docId=oauth2§ion=EmbeddedOauth2Launch
(deleted)
Don't ask the same question multiple times please?
The launch token is not a security feature, is just a way to convey context from the EHR to the app.
The step of the workflow after receiving the launch
parameter is to authorize with the auth server. So at that point the auth server will know who the user is and can verify that the launch
value they submitted was associated with them.
Are you both saying that the context communicated from EHR to the external app does NOT include the logged in user session? Meaning- the practitioner would have to enter their credentials into the browser again?
My understanding up to this point has been that the launch parameter kinda doubles as an "SSO" credential so if the EHR is a thick client and/or mobile app- the practitioners EHR session would be extended into the browser.
If I'm right about that- that's where I can definitely see some security challenges to mitigate (which i've seen strategies for)- but first wanted to confirm my understanding.
(deleted)
(deleted)
The launch parameter is opaque to the app and doesn't include identifiable information.
The EHR should not treat this as a credential, or an access grant, but rather as a correlation handle for an authorization that's happening in the usual way (authorization code flow).
There is probably more guidance that we could provide (potentially: cross check any launch context with the permissions of the authorizing user) but since we don't mandate the semantics of this field, we leave it to EHRs to use it as they deem appropriate.
The threat model is: an app or user can mess with this value before it's supplied to the authorize endpoint, and the EHR should be robust to that.
that would be a good security consideration to mention, in addition to a warning to make sure the value is opaque. EHR can handle that in many ways that don't need to be elaborated upon (e.g., signed, a hash, nonce, etc).
Currently we document:
In an EHR launch, an opaque handle to the EHR context is passed along to the app as part of the launch URL
Opaque identifier for this specific launch and any EHR context associated with it
opaque is read by some as okay to include understandable stuff, with expectation the user will not look closely. Much like an OID, UUID, or URL. So we might want to be more specific than opaque. No idea what words better explain that the value must not be understandable by the client.
must not be tamperable
Maybe this?
Servers should design their launch
parameter implementation with the assumption that malicious actors may attempt to replay, tamper with, or infer sensitive information from these values. Key security properties to consider include uniqueness, integrity verification, and protection against information disclosure. Implementers should ensure their design is robust against scenarios where the launch
parameter might be intercepted, manipulated, or forged before being presented to the authorization endpoint.
The attack I've described above is NOT a replay/tamper attack, let's say the launch token is a random value and it can only be used once. A bad actor could still get access to a valid token and then can try to use it to associate wrong account with the patient record, or it could be intentional as well where a user shared their token with another individual. I think it is important to mention that the EHR system should have some logic implemented to verify the identity of the redeemer of the launch token when issuing the authorization code.
Since the launch token is sent as a query parameter in the URL to the authorization server, it is susceptible to leakage, for e.g, when using referer header, this information will be leaked if a user visits subsequent pages controlled by the attacker. The launch token is not transmitted securely to the authorization server. It should maybe use back channel for it.
Thanks for the clarification, @Josh Mandel - spending most of my time in the standalone flow- i was not aware that the user will re-authenticate in the browser during an EHR launch flow. That helps a ton, as it means that we can at least trust that the user is valid, and the EHR can then ensure that the launch context is valid for that user (as called out), and underlying permissions are enforced as well.
brg-shrngi said:
The attack I've described above is NOT a replay/tamper attack, let's say the launch token is a random value and it can only be used once. A bad actor could still get access to a valid token and then can try to use it to associate wrong account with the patient record
The launch value doesn't associate accounts with records. Do you think it would help to add the following to the suggestion above?
Sservers must not treat the launch parameter as conferring access rights; authorization decisions should be based on the authenticated user's permissions, not solely on the presence or content of a launch token.
it won't hurt to say that, even though it should be obvious
Josh Mandel said:
The launch value doesn't associate accounts with records.
The launch token doesn't directly establish the association but it helps getting the authorization code and access token which can be used for establishing the association.
I think we should also share that the launch token is susceptible to leakage (because it is transmitted in URL), and we can maybe suggest some mitigations for e.g., by asking the user to sign in again
I'm not following what the launch token has to do with the authentication context. The launch already/always includes an authentication step.
"leakage" is already covered by the proposed language
assumption that malicious actors may ...
The phrase "infer sensitive information from these values" implies that if the token contains sensitive information, there’s a risk of leakage. It’s important to highlight that the token itself could be compromised, even if it’s designed to be random, unique and used only once. The client application needs a mechanism to send contextual information to the EHR authorization server for verification. This will ensure that the entity redeeming the launch token is the same user for whom the token was originally generated.
I am not sure I follow what you're suggesting here. Are you proposing that we add additional explanatory language or are you proposing that the specification needs new functionality?
We should add some explanation to clarify the language ensuring that readers are aware not only of the security risks but also of the potential impacts of this implementation.
Regarding functionality, I see a security flaw in this algorithm. I think we can implement a mechanism to link the requests to one another. For instance, the OAuth authorization code flow helps mitigate authorization code injection attacks, where a malicious actor could swap authorization codes to log into someone else's account by using PKCE parameters to protect the token exchange flow. We can use a similar approach for the launch token, by using code verifier and code challenge in the requests to ensure that the entity redeeming the token is the same entity who started the flow. Additionally, we can also recommend that the launch token should be transmitted via a back channel, which is a more secure option for sending the token to the authorization server.
Alternatively, we could remove the launch token step from this flow and instead obtain user consent directly in the EHR application. However, this might make the process similar to a standalone launch. Please let me know if my understanding is incorrect here.
We already have pkce. I can't tell if you're advocating for that or for something analogous that runs in parallel.
I'm not sure I understand the actual threat you were describing.
I understand this implementation is based on OAuth authorization code flow but it adds a step where launch token is required to be sent to the authorization server. PKCE parameters are not used when launch token is being exchanged
with the server hence this step is vulnerable to code injection attacks. PKCE is used in the later steps where request is being sent for authorization code and access tokens.
That's accurate re: PKCE.
I think the concern you are articulating is a kind of substitution attack on the launch
value. But substituting a different launch value should never enable an app or user to accomplish anything that they could not accomplish before. It does not authorize the app to see any new data, does not leak sensitive information to the app, etc.
Given the advice we drafted above, what is the residual threat that we need to mitigate?
it's not a security threat, but it might be a clinical threat - mixing contexts - specially in the case where patient-banner is true - could result in disastrous clinical outcomes
on the other hand, it really seems like a marginal threat in practice
The user tricking herself is not a threat. And if the app wants to trick the user about context, it can simply lie, not without actually manipulating the context; the user doesn't see this information directly, but only as mediated through the app's UI.
This is true, but @snahil is elucidating a risk that an attacker could intercept and change the launch context between the EHR and the launched app, so that an app that is (rightly) trusted to not do things like actually does that anyway
I think it is a possible theoretical attack but wow a lot of work for a limited outcome.
Let’s consider an example: Alice gains access to the launch token issued for user Bob. She generates a linking request from her client application, intending to send a launch token to the EHR authorization server. However, Alice swaps the original launch token with the one she stole from Bob. When the EHR authorization server receives the request, it has no way to determine whether the request is coming from Alice or Bob becuase it only receives the launch token (no other information). It verifies the launch token and issues an authorization token. Alice then uses this authorization token to obtain an access token, allowing her to link her account to Bob's patient record and gain access to all of Bob's data.
nah, not that
the launch token does not allow her to link her account to bob's record. The approval for that is in the AS, independent of the launch context
Launch tokens are not authorization grants. The server does not issue an authorization token on the basis of the fact that a launch token was provided in request. The server issues an authorization token only when a valid authorization code is provided, and an authorization code is only available to Alice if she has successfully authenticated and authorized the app to launch.
The threat Grahame Is describing makes More sense to me, but it involves a third party being able to intercept an app launch... At which point the user's device or session or app is compromised (i.e., similar threats could be carried out without having to go through this injection dance).
I agree that if you're compromised, you're compromised, and there's very higher gain threats than the one I described in that case
but I was thinking that there's a chance that you could inject a proxy with a DNS poisoning attack that can get at the launch context and not get at any other part of the request. In which case, my attack becomes the worst thing you can pull off.
But if you have a proxy that can MITM the SSL and get at the launch, this comes back to 'you're compromised', with all the consequences of that
Josh Mandel said:
The server issues an authorization token only when a valid authorization code is provided, and an authorization code is only available to Alice if she has successfully authenticated and authorized the app to launch.
Alice has a valid user account in the client application and successfully logged in and authenticated. She then authorized the app to launch but used Bob's launch token in her request instead. @Josh Mandel why do you think this scenario is not possible?
Thank you for sharing that case report BTW -- terrifying stuff. AI summary:
This case involves the death of Paul Lau due to a medication error at Macquarie University Hospital in 2015. The error occurred when an anesthetist, Dr. Kim, mistakenly prescribed high-dose opioids intended for another patient to Paul Lau's electronic medical record. This is a clear example of a context error in healthcare IT systems.
For what it's worth, this is part of the reason that we did not try to tackle communication of context switches to a smart app once it has launched (rather, we provide a mechanism where the app can be closed and relaunched in another context).
Alice has a valid user account in the client application and successfully logged in and authenticated. She then authorized the app to launch but used Bob's launch token in her request instead.
I'm following along so far. In this scenario, Alice has gained access to a launch token that was issued in association with Bob's session. According to the guidance above, this is not going to give her access to anything she would not otherwise be able to access.
We could encourage the EHR to bind the launch token to a user context, and to reject an authorization request if the user does not match the initial context. I'm not sure what this buys us but we could incorporate that into the proposed language with a sentence like
Furthermore, servers should bind launch parameters to a particular user and reject authorization requests where the authenticating user differs from the user bound to the launch parameter.
Thank you, this language would surely help readers to understand the security risk and its potential impact.
Josh Mandel said:
According to the guidance above, this is not going to give her access to anything she would not otherwise be able to access.
To address your concern, once Alice obtains Bob's launch token, she can create a valid account linking request using that token and send it to the server. A valid launch token signals to the authorization server that the user has consented to account linking and is requesting an authorization code. However, the server has no way to verify whether the request is coming from Alice or Bob, as it only receives the launch token without any identifying information. If the launch token is valid, the server issues an authorization code for Bob, which is then sent to Alice. She can use this authorization code to obtain an access token for Bob. She then uses the access token to send a linking request that includes her account information and Bob's access token. The server, recognizing the access token as belonging to Bob, mistakenly links Bob's patient record to Alice's account.
Stealing a launch token from another user can have a cascading effect, potentially leading to unauthorized access to that user's authorization code and access token. I would like to share that we were able to successfully test this scenario in Epic's sandbox environment for EHR launch.
She then uses the access token to send a linking request that includes her account information and Bob's access token.
We do not define an account linking request, and no launch
that Alice presents to the authorization server can cause her to have access to data she would not otherwise have. This is because the launch value is not an authorization grant.
I'm still not convinced that servers need to bind launch values to user sessions. I say this with an understanding of the dangers of session fixation attacks and of the effects that cascading assumptions can have in the overall security of a system.
I don't mind incorporating the guidance above, but I don't think we should imply that a server cannot be secure without this binding -- unless of course someone can explain why this is the case.
In the scenario described above, what do you think Alice would need in addition to Bob's launch token to obtain his authorization code and eventually his access token?
She would need her own account to authenticate to the system, and then she would approve access and then the app would get an access token bound to her account.
She could not receive an access token bound to Bob's account.
(not without being able to authenticate as Bob)
@Josh Mandel are you referring to the step "Authorize app (MAY include end user authentication and end user authorization)" in the flow diagram linked here - http://hl7.org/fhir/smart-app-launch/2021May/#smart-authorization-sequence ? The explanation says "The authorization decision is up to the EHR authorization server, which MAY request authorization from the end-user."
But the above link is from May 2021, the latest doc here (https://build.fhir.org/ig/HL7/smart-app-launch/app-launch.html#response-4) doesn't have this step or any flow diagram but it only says "The authorization decision is up to the EHR authorization server which MAY request authorization from the end-user".
Is there any reason why the step says "MAY" instead of "MUST" ?
I believe the wording should be changed to "The server MUST seek authentication and/or authorization from the end user before issuing the authorization code to the application."
The color on this is that there is always an authentication step but it may be automatic if the user already has a session established -- and ditto for authorization. Both of these steps occur but they may not involve any user interaction. This is a very common case for the ehr launch because ehrs don't want to interrupt their users with a reauthentication step or a reauthorization step every time an app is launched. Policies can drive the authorization (e.g., remembering previous decisions or implementing an organizational choice).
Nevertheless, the launch will fail if Alice is not authenticated properly.
A user may not always have an active session with the EHR, especially when sending request from a mobile app. Therefore, the standard should mandate an authorization step. This step can be implicit if the user already has an active session with the EHR server, or explicit if not. The May 2021 version was clearer, as it included this step in the flow diagram.
If they don't have an active session, then the authentication is explicit
If we're confident that the correct user is authenticated/authorized in the browser, then it seems like this threat is similar to a "cross site request forgery" style attack where an attacker might trick a valid, logged in user to act on data they didn't intend to act upon (injecting a launch context that's different than the user created with their action in the EHR). I would agree that this type of attack, on it's own, seems pretty low risk here, since there are a number of steps that all this stuff flows through before anything actually happens, and the EHR would have plenty of opportunity to catch it.
Josh Mandel said:
If they don't have an active session, then the authentication is explicit
I think it's really important to note that, in a native/mobile + web situation, that the active session in the application, and the active session in the browser are completely separate, and that the launch parameter is not trying to bridge them together. If the launch parameter is used in any way to extend that mobile session into the web, then the risk/threat is way higher.
In mobile apps (or where user does not have an active session with EHR hence no implicit authorization), this would allow a bad actor to steal an unused, valid launch token from another user and link their account to that user's patient record and obtain access to all their information.
Also, without user authorization how does the server confirm the scope that needs to be associated with the tokens it provisions to the client app? The standard is somewhat not very clear about these aspects.
If the launch parameter is used in any way to extend that mobile session into the web, then the risk/threat is way higher.
The launch parameter does not establish a session. It needs to be consistent with (or at least not inconsistent with) the session that the EHR does establish during the authorize step.
steal an unused, valid launch token from another user and link their account to that user's patient record and obtain access to all their information.
Again, launch tokens are not grants. They don't give you access to any information you can't already see.
in a native/mobile + web situation
How are you doing EHR launch with a native/mobile app?
I'm not with an EHR- so my personal experience with this type of thing actually stems from use cases outside of healthcare. The case I'm referring to is where the user is logged into a native mobile app (or desktop app- doesn't matter), and the user clicks on some sort of button within the app to launch a third party app, but that third party app runs in a browser as a web app.
The native/mobile app will then either launch the browser, or use an embedded browser to show the content from the 3rd party. From the user's perspective, the user expects that to be a seamless process, and they expect to not have to login again (it's all one app, right?). However- what's actually happening is that this use case now becomes an omni-channel use case, and great care must be taken to ensure that the user's logged in session is properly instantiated within the browser.
I had incorrectly understood that the EHR launch flow would be used to offer such experience. If the EHR launch flow requires the user to login separately to the launched web app at least once- then a significant attack vector is out of the equation. I was merely calling out this use case specifically because it's easy to get things mixed up.
The native/mobile app will then either launch the browser, or use an embedded browser to show the content from the 3rd party.
This is where the EHR is native/mobile - and it is surely something that exists -but I was asking about the _SMART app_ being native/mobile - I don't think you can even do an EHR launch in that case? (or if you can - how?)
Oh interesting @Michele Mottini - I can't say that I've seen that in healthcare, no. I'd say the closest thing to this would be outside of healthcare there's this concept of a "magic link". It's generally seen in cases where someone forgot their password, or performs a passwordless "login with email" type of login flow.
So in the browser (or potentially an email application)- the user clicks a link called a "universal link"- which is a non http:// URL that the mobile OS associates with an app. Whenever a user visits one of these special URLs, it's treated by the mobile device as sort of a "deep link" to the native mobile app. There's a fair bit of security and hoops to jump through with apple/google to get your app associated with a universal link.
So theoretically, I could develop a mobile app, and there could be a launch URL like this: "dansawesomeapp://launch", and if a user clicks on that link within a browser on a mobile device, my mobile app would pull up, and it would begin the smart launch flow automatically.
Perhaps we'll see more of this in the future within the context of smart launch, but I personally haven't at this time.
but was asking about the _SMART app_ being native/mobile - don't think you can even do an EHR launch in that case? (or if you can - how?)
I don't know if this is done in the real world, but technically a mobile SMART EHR could open a system browser context onto the launch URL of a mobile smart app; if this is an app-claimed URL and the app is installed, then the app would be opened and would proceed by parsing the launch id from its context to initiate an authorize request.
(Again, this launch is is not an authorization grant and proceeding to authorization will lead to a user authentication + authorization step as determined by EHR policy.)
Like taxes, delays at Schiphol, and other things in life, the Chocolate SIG seems inevitable. But unlike the others, chocolate has a meaning and purpose, and does not(1) leave that feeling of void.
For security, today we have individually packaged chocolates. Of course, that SupplyDelivery is handled by OO. The delivery period is between Q3 and Q4 today.
(We don't care what's inside, so no need to debate which resource we'd use for that. SupplyDelivery is enough).
Provenance includes 3166-1-2#CH
(1) because the Provenance does not include #BE this time, the feeling of fulfillment is NOT as guaranteed
Is there a binding of the chocolate to a Location so we know where to find them, or at least a SearchParameter?
....so, is it happening? Today afternoon or tomorrow? I'm not carrying these Belgian goodies back.
....or do we need to create a NutritionOrder?
heck you can leave them at reg desk when you leave!!!
The Swiss will join!
This is a mustSupport event.....
🇨🇭 🇧🇪 🍫today at 🍪 break close to reg desk @Jose Costa Teixeira for any 🍫 lovers ..
And in DevDays?
@Michaela Ziegler did you already book a room? Thursday 15:15 to 15:45, right?
Mikael Rinnetmäki said:
Michaela Ziegler did you already book a room? Thursday 15:15 to 15:45, right?
Yes, it will happen in the BrightLab on the 1st floor :chocolate:
:flag_switzerland: chocolate will be there ...
Just a reminder in preparation for Dallas
I'm picking some up tomorrow!
@Jose Costa Teixeira swiss chocolate is on the way to dallas
@Michaela Ziegler also Belgian Pralines :)
And some world-renowned Wisconsin chocolate.
I bought some Australian chocolate
macadamia and something
What time slot suits you all for a meet and eat? :chocolate: :smiley:
Tue, 3 p.m.?
I think so. Tuesday at 3 pm.
In one of the rooms around the coffee area?
Yeah, I could organize room C :chocolate:
@Grahame Grieve @Gino Canessa ok for you?
also on whova
That works, thanks!
works for me
thanks all for joining us and thanks @Jose Costa Teixeira @Grahame Grieve @Gino Canessa @Line Saele for bringing the chocolate :star_struck:
PXL_20240521_201349752.MP.jpg
Look at those very very happy people who got chocolate! <3
....and it's that time of the year again :chocolate: :love: :tada:
Does anyone have preferences or constraints on when to meet and share?
tomorrow? thursday?
both fine for me
perhaps at the end of the lunch break?
afternoon break ?
Q5 Thursday?
PS José is 20 cm next to me .. I don't know why we are typing :rolling_on_the_floor_laughing:
Tomorrow afternoon break?
please post a nice picture :cowboy:
Michaela Ziegler said:
please post a nice picture :cowboy:
We miss you and Oliver ...and CH chocolate :-)
but I know that Roeland is around
Giorgio Cangioli said:
but I know that Roeland is around
I reminded @Roeland Luykx to bring chocolate :yum:
I have chocolate. Not exiting one, since I forgot until I arrived at the airport in Norway.
An I miss you @Michaela Ziegler - please come to Madrid! We need a Cava SIG too!
I have chocolate over from the HL7 Europe meeting. Will bring it.
Memo to self: bring Dutch chocolates to Madrid.
lets instantiate the Chocolate SIG for all WGM's!
Well????
@Roeland Luykx
@Giorgio Cangioli
where are you?
At the registration desk
4th
Inside the ballroom
This is a discussion thread regarding the requirements for tools using the shared .fhir/packages registry.
Many tools are installing packages in this directory and relying on packages installed by other tools, but some behaviours (the content of packages.ini, the addition of indexing files), can lead to conflicts, particularly if multiple processes are trying to utilize this directory at the same time.
.lock file usage is used by the java core libraries (Validator, IG Publisher), but this is, as @Josh Mandel pointed out could be needlessly complex and avoided altogether if package installs were guaranteed to be an atomic action (install into a temp directory in .fhir/packages
, and then rename) and idempotent (I don't care if another process installed a package over the one I just installed, because they will be guaranteed to be exactly the same).
What if we maintained that all tools should NOT be able to alter the content of installed packages, and should limit their own data to a subdirectory (for example .fhir/packages/.firely
)?
Aside from package installation, this would also neatly prevent file name collisions (.fhir/packages/.hl7/my.package#1.2.3/some-new-file
doesn't interfere with .fhir/packages/.firely/my.package#1.2.3/some-new-file
) and means each tool just needs to implement concurrency within its own directory.
(deleted - accidental double post)
No idea why zulip posted that twice. Apologies.
can we live without packages.ini?
as for indexing... I thought that we did that before install? can you check?
I'm imagining a scenario where a pre-existing cache contains packages from previous implementations. How would we know that the packages are still compatible with the current way of doing things? packages.ini with a simple version is a good way of explicitly stating what particular interactions are supported in the cache.
that's true. There wouldn't really be contention around a packages.ini that only contained the cache version?
I'll have to dig into the indexing as it was changed in recent merges, but my memory is that it generated missing indexes on package read, which was what necessitated re-arranging it.
If it only contains a package cache version, maybe it needs to not be 'packages.ini' at all.
but my memory is that it generated missing indexes on package read, which was what necessitated re-arranging it.
we can change it to only do it before the package is renamed.
If it only contains a package cache version, maybe it needs to not be 'packages.ini' at all.
gonna be something though
cache.version?
could be. I don't mind, but the name and format aren't germane to the locking discussion?
we can change it to only do it before the package is renamed.
This assumes then, that all other tools will also index before renaming. It would require it, in fact, and that the indexes produced are always the same.
Which I think will guarantee headaches.
And yeah, I don't care about the name. All I'd care about is the existence of something to indicate cache version.
Well, I do care about the name, a lot actually, but that discussion doesn't need to be here
that the indexes produced are always the same
there is a spec for the index, but I do deviate from it :-(
@Martijn Harthoorn maybe we should talk about that
the documentation for the index file says:
The files array contains an object for each resource in the package with the following properties:
* filename - the filename in the package directory that is being described
* resourceType
* id
* url
* version
* kind
* type
* supplements
* content
but i had to add:
So all of the above needs to be satisfied, and:
The .index.json file can be rebuilt at any time
I can imagine the pain of sushi generating a bad index (not to imply that sushi would be prone to this) and then some other component having to deal with that. Or doing something (like above with valueSet) that gets overwritten by some other tool.
Tagging @Chris Moesel at request
And @Marten Smits is currently maintaining the .NET packaging library, so I am adding him too.
SUSHI does not generate its own packages. We only cache packages that we have pulled from a registry or from the build server (for #current builds). When we do so, we follow the approach that Josh suggested, unzipping the tgz into a temporary folder and then moving it to the correct location in the cache. We don't modify anything in the package, except fixing up the folder structure in a few old packages (as described here). SUSHI doesn't generate, modify, or even read .index.json files.
thx
:+1: for the temp folder approach. That indexing (or lack of indexing) behaviour is probably why Validator / IG Publisher builds its own, right Grahame?
builds its own what?
Indexes. If it finds a package installed by sushi, without indexes, thats when it would build them.
@David Otasek - Generally speaking, I think that packages have a .index.json file in their distribution package, so when we cache the unzipped package, it usually already has a .index.json in it. That said, I don't know when that started happening, so I guess any packages prior to that wouldn't have one.
that's the case - it was about 5 years ago
@Chris Moesel yes, that's my understanding as well. Sushi is doing a very literal install of the package, while the core libs are 'enhancing' it for optimization purposes. My proposition above was to do what Sushi does, and if .index.json or whatever is generated from another tool, it should go in .fhir/packages/.tool-id/
to keep the package install idempotent.
why need to do that if the index is generated prior to renaming?
That would have to be a requirement for every tool, then.
or we could delete and reinstall the package. Though that's not really the idea
I'm not excited about that idea. Though not exactly the same, that has the same feel as the package clearing that was causing us grief.
With the .fhir/packages/.tool-id
approach, I'm mostly attracted to the idea that the package will always be the same, and that different tools will have their own sandbox to do whatever they want. If I recall correctly someone mentioned they were maintaining some additional data of their own, which is exactly what we don't want.
that's firely - @Ewout Kramer
That sounds right.
Yes, we Firely also generate a .firely.index.json file which contains a bunch of stuff we add for optimizing our tooling. We also still generate the .index.json as described by the spec. We used to add our own stuff there too a couple years ago, but I decided to keep that just as described by the spec so that other tools still work.
@Marten Smits what do you add? Can we converge?
Let me check.
First of all, we put our index file at the root (so next to the package, example, and 'other' folder). So we have one index file for the entire package.
We add the following extra fields:
Most of these we use the make resolving files from the packages faster.
sounds like we can converge on that
You've added
valueSet is CodeSystem.valueSet - again, for resolving things
I can't see that I make use of derivation. So I don't know why I added it
oh no, I do. I use it to find/explore the type hierarchy without having to load all the structure definitions
Ok, that's easy enough indeed to align.
Do you want to keep having an index file per folder? Or no problem with moving it to the root?
I think I put it in each folder because we didn't say, and it seemed the most conservative option. But it does matter to me - I don't load examples unless examples are being looked for, for example
Sure, we can work around our root scope I guess.
Do we need to file a Jira ticket to change the index.json spec?
yes we do need one
For clarity, the full proposal here is that every tool installing a package to the package cache will:
.index.json
file, as defined by the spec mentioned (which will be updated)I'll go on record as saying I wanted tools to keep their dirty work to their own directories (.firely, .hl7-core, .sushi), but I can be on board with the above if that's the consensus.
@David Otasek I'm not sure, but if you're proposing adding requirements on how packages are created too, we'll need some FHIR-I tickets to update the requirements on https://hl7.org/fhir/packages.html
For now .index.json
and package.ini
are not mandator (or described in the latter case). But perhaps you are not proposing to make them mandatory in publishing, but in that case maybe you could update the proposal wording above to reflect that :thank_you:
Yes, this is restricted to tools writing to the package cache, and I updated the proposal above. I think that falls out of FHIR spec territory. I believe .index.json will still remain optional, and Grahame has stated that we will need a Jira ticket to make changes to that spec.
even though they are not mandatory, I always populate them when publishing
Well, actually the language in the package spec is intentional at saying tools can modify these indices at any time. Fine as long as they aren't in the package cache. If they're in the package cache, there will be a VERY specific point at which they can be changed, and then must remain static unless completely deleted.
I don't like that the package spec says something which is immediately contradicted in the package cache docs, but doesn't otherwise mention it. Maybe a note saying: "there are stricter rules regarding regenerating indices when utilizing a package cache".
At least a breadcrumb.
We don't support package.ini I think. Can someone explain what's its purpose?
it has two purposes - one to mark the version of the overall repository. that's currently 1
and second to track the last use date of packages, so a user can see which packages haven't been used.
but that's not really doing anything about the moment
In reviewing the Sept 2024 ballot I have found value sets and code systems in IGs intended for implementation with the "Experimental" flag set to true. Granted they are early in development, but looking at the content represented in the value set it is clear that the codes can be used and are expected to be used. A Code system example of this is Healthcare Capacity Reporting Code System. A particularly egregious occurrence of this can be seen in the Information Recipient Extension that binds the Clinical Document Participant Types Value set value set REQUIRED but the value set is marked Experimental.
In both the code system example and the value set example the use of the Experimental flag only confuses implementers. I suspect the "information" intended to be conveyed is already communicated by the maturity of the resource and the fact that this is an early IG.
I'd like others to comment if they agree with me on this and would like to push IG authors to stop using Experimental when the content is actually just an early initial attempt at real stuff. @Grahame Grieve @Lloyd McKenzie could we put in publisher warnings on experimental code systems and value sets? Particularly when publishing. Particularly when bound REQUIRED?
I noticed this on some other resources. I think authors are incorrectly using experimental=true to mean really, really draft (or even the same as draft), rather than the defined meaning of "for test purposes."
ShareableValueSet and ShareableCodeSystem profiles had it mandatory, so several authoring tools have insisted having it filled in with something. A draft value set is not automatically experimental, but authors mark it as such "just in case". And then it gets forgotten.
I think nothing should get into THO with "experimental=true". The only things in other IGs where it would be true is if it's an example and not intended for real use.
So, add warning for experimental resources and a FMG/TSMG waiver needed?
I would say that THO should error on experimental. Other IGs should error on experimental that isn't marked as an example, and warn on examples that aren't marked as experimental.
hmm. I thought I already had a warning when something not experimental refers to an experimental value set
. would like to push IG authors to stop using Experimental when the content is actually just an early initial attempt at real stuff.
I think there's cases where content or even the value set it self is experimental, even while it's clearly in the space of something that is intended to be implemented, so I suspect that we shouldn't have hard policies about that
and I don't think that they should be errors, or if so, not until later in the process, and we aren't executing on IG maturity yet
If it is an error, I would request that be done in the HL7 template, rather than IGPublisher or the base template. I can imagine people wanting to publish experimental resources even if we don't agree with that decision.
I can do errors that are driven by HL7 policy in the validator, there's already a few like that, where the rules don't apply to content published by other organizations
Oh, I thought those were driven by the template. That works for me too.
so it turns out that the validator has not been checking the experimental flag on bindings, so from the next version:
Grahame Grieve said:
Is that warning for any binding to an Experimental flagged value set that is not experimental? If so that is fine but far from meeting my concerns. We should be warning on all experimental value sets and code systems in ballots and published IGs. And an error when a required binding to an experimental value set.
a warning when binding to an experimental value set from a profile that's not experimental
I don't believe that it should be an error - it's not always wrong
Grahame Grieve said:
I don't believe that it should be an error - it's not always wrong
It would be wrong when the binding is required.
really? always wrong? why does binding strength make a difference to whether it's experimental?
Perhaps in part we are quibbling over where to communicate "experimental", a required binding to something that is never to used in a real system seems like technical testing, not standards IG. I just think that type of combination is a nonsense thing for an HL7 IG. By that I mean more than something purely for technical work. I'd like to hear from others on this.
It's totally fine for an experimental profile to have a required binding to an experimental value set (and code system). I.e. you just have something made up as an example for all three.
'experimental' should jive with 'example'.
There’s two levels here. First, should there be non-example experimental resources. Second, should a non-experimental resource be able to reference an experimental resource (value set, profile, extension,…).
I think the validator discussion above is only addressing (part of) the second. Is there a validation warning (HL7 error?) of the first?
I don't think non-example experimental makes sense. You could have 'draft' non-examples if you want to say "this is intended for real use, but isn't ready yet". But if it's not an example and it's not draft, I don't think it has any business being experimental.
I suppose you could have an example binding to an experimental value set. I.e. "Here's a set of codes to give you an idea of what kinds of concepts you could represent, but you shouldn't actually use these codes". That's the only use-case I can think of.
I am still not clear on the difference between experimental
, draft
, and FMM. For example, I might argue that everything that is not a release publication should be marked experimental
because they are not intended for production use.
Do we just have too many ways of saying the same thing?
Experimental = not for real use (now or ever)
Draft - in development, not yet ready for use
FMM 0 - should be same as status = draft
FMM 1+ (status should be active or retired) and indicates the degree of adoption and stability of this thing that is ready for use
status of retired = this thing should no longer be used
Something that's experimental shouldn't have an FMM
Well, I can see why everyone is confused at least. Having a structure with a flag experimental
and the short of For testing purposes, not real usage
, gave me the expectation that it aligned with my use of the term experimental: that something is not ready for production yet.
I am not sure reading the longer descriptions that there is anything to actually indicate that meaning. I definitely cannot see anything that indicates we can never change the value (e.g., in a future version).
experimental vs draft really does need to be made more clear.
I definitely cannot see anything that indicates we can never change the value
We have never said that
Lloyd McKenzie said:
Experimental = not for real use (now or ever)
I assume I am misreading that then - what is the intention?
Gino Canessa said:
Well, I can see why everyone is confused at least. Having a structure with a flag
experimental
and the short ofFor testing purposes, not real usage
, gave me the expectation that it aligned with my use of the term experimental: that something is not ready for production yet.
I think the idea behind experimental is that you want to be able to send it to a system for test purposes and be able to quarantine it.
However, why canonical resources are special in this regards, compared to regular resources which don't have the experimental flag, I'm not sure.
I assume I am misreading that then - what is the intention?
the intention of the author is that it won't change. Unless the author changes their mind. We would expect that to be unlikely, but not wrong
Elliot Silver said:
I think the idea behind experimental is that you want to be able to send it to a system for test purposes and be able to quarantine it.
I was under the impression the best practice for that was using the Core Security Label of HTEST
.
Grahame Grieve said:
I assume I am misreading that then - what is the intention?
the intention of the author is that it won't change. Unless the author changes their mind. We would expect that to be unlikely, but not wrong
Fair enough - it sounds like the intention for experimental
is a classification-type element (like abstract
or kind
) and not a status element (like status
), and thus explicitly not a lifecycle state that will end in a production structure?
I think we definitely need a ticket to clarify - has someone filed one already?
thus explicitly not a lifecycle state that will end in a production structure
yes, that's the intent
and I agree with @Robert McClure that it's not being used correctly in these cases. I have added two things:
If I say "this is experimental" then you should assume "there's no intention I'll ever use this in production", not "it's not yet ready for production". If I change my mind and decide "you know what, I think this actually should be used in production", then I could drop the experimental flag. That's very different from draft non-experimental which is saying "I intend this to be used in production, but it's not ready yet".
Lloyd my confusion is that 'experimental', in my experience in software, is a status. It is equivalent to saying something is alpha/beta/etc.. E.g., something that is not ready for production yet (not that any such labelling actually prevents it from being production - to the consternation of software developers everywhere :-)
I even have a branch in a repo named experimental
that I am merging into the main
branch this week. It was experimental while we figured out if it could work, and since it does it is no longer experimental =). The intention was to see if something would work - but the intention was always to promote it if it did.
My understanding through this thread is that StructureDefinition.experimental
is classifying a structure as a type of definition that is never expected to move into production. That is new to me, and given that this thread is about overuse, I assume will be new to many others.
*edit: to clarify - I am familiar with 'experimental' things that are just Proof of Concepts or other such terms. This is just not language I associate that way (and assume others have not either).
I agree that the element name isn't the best for what it represents, but we're past the point where we can change it.
Agreed - we should update the descriptions to clarify and was wondering if anyone in the thread has filed a ticket already (was discussed) or if I should.
Not I :smile:
Lloyd McKenzie said:
I don't think non-example experimental makes sense. You could have 'draft' non-examples if you want to say "this is intended for real use, but isn't ready yet". But if it's not an example and it's not draft, I don't think it has any business being experimental.
I suppose you could have an example binding to an experimental value set. I.e. "Here's a set of codes to give you an idea of what kinds of concepts you could represent, but you shouldn't actually use these codes". That's the only use-case I can think of.
Can I ask that we don't have a Warning when we have example binding strength with an experimental valueset? We created some ValueSets as experimental and used example binding for two three reasons:
a) give the community an idea of what we are looking for
b) get feedback
c) there is not a definitive list of codes that we can find or agree on just yet
By using example, I feel we are saying 'we really don't know if this is right yet, but maybe these work, give us some feedback please'? So flagging that as a Warning seems wrong.
After reading this thread CG is not sure on what element to use to flag ValueSets or CodeSystems which could change in the future.
One example is our TBD Codesystem which contains all concepts/codes which do not have a loinc (or other external terminology) code (yet).
This CodeSystem is actively used inside the IG and is implemented by several stakeholders.
So experimental seems to be the wrong element to represent this. We discussed in the WG the option of using the draft status or the SDStandardsStatus Extension with the trial-use code.
Downside of draft would be that some tooling, e.g. hapi, only loads active resources from an IG.
Your TBD Codesystem seems like it is something which you intend to be temporary. The concepts themselves won't be temporary, but the actual code system as it currently exists will not. The official policy from TSMG (https://confluence.hl7.org/display/TSMG/Terminology+Expectations+for+IG+Developers) is that something like your use case SHOULD be marked as experimental.
Thanks for the guidance.
Marc Duteau said:
Your TBD Codesystem seems like it is something which you intend to be temporary. The concepts themselves won't be temporary, but the actual code system as it currently exists will not. The official policy from TSMG (https://confluence.hl7.org/display/TSMG/Terminology+Expectations+for+IG+Developers) is that something like your use case SHOULD be marked as experimental.
Interesting. I had expected that the CodeSystem itself would be active, with individual concepts would be retired as they get migrated into other systems.
Elliot Silver said:
Interesting. I had expected that the CodeSystem itself would be active, with individual concepts would be retired as they get migrated into other systems.
The code system described is active even if marked as Experimental. Experimental is not a status. I agree we should consider giving guidance that when the concept represented in the temporary is "transitioned" to a the 'real' intended code system (like LOINC or SCT) the concept in the temporary code system could be retired to reduce user confusion: IE - stop using this code system representation of the concept.
Agree, but I don't see a reason to indicate it as experimental. The code system isn't for test purposes. It represent a real code system, even if the concepts in it aren't long lived.
@Elliot Silver Good point. The code system apparently has a persistent useful domain therefore the code system described is not temporary, just the concepts within it are.
This is a topic from FHIR Connectathon 37 IPS Track, but expected to run past the event. The IPS sepcification sets a minimal baseline of data expected for a summary (e.g. you must include active, allergies, meds, problems see https://build.fhir.org/ig/HL7/fhir-ips/Generation-and-Data-Inclusion.html#data-included-in-ips-documents). The IPS does not intend to give programmatic guidance to all the relevant data in a summary and this is left up to implementers / use case.
We're inviting connectathon participants (e.g. @Allana Cameron ) and other on Zulip to contribute here any rules or guidance that they may have in regards to what should be in a summary. We could use this in the future to update the list of external links in the guide in the future, although we do not plan to include any direct guidance for what to include in the near future.
In Canada, we currently have three provinces who have worked with their clinical working groups to determine how much content to include within each of their selected data domains. I have sent emails today to confirm their final content and to retrieve permission to share with this community. I'll keep you posted.
When we did some of the original work with HAPI, we developed a very coarse set of rules to filter out some information for the summary. These are shown here and further refined/editable in the HAPI documentation
Yes. The rules in HAPI are a starting point. It's expected and desired to have further discussion and contributions to this, as we all are learning from our various implementation experiences.
From the Australian perspective, findings from Sparked Accelerator: Rural and Remote Health Equity Roundtable session 17-18 July 2024:
Note: These findings need to be worked through in terms of specific data elements, terminology, and appropriateness for IPS.
Sparked priories for IPS
Patient summary is being discussed for augmentation or replacement of for the following:
Top two priority data sets identified
Across there two priorities, the following ranked list was obtained from the participants:
Detailed notes from the Rural and Remote Health Equity Roundtable can be found here https://sparked.csiro.au/wp-content/uploads/2024/07/Sparked-Rural-Remote-Health-equity-Roundtable-July-2024-Workshop-Transcription-For-Publication.pdf
@Ryan Mavin that's a very comprehensive list. I find it difficult to believe that anyone would ever actually populate all those usefully.
And to demonstrate that I'm just as guilty, there's nothing there about independence skills, which is very important for aged patients
Grahame Grieve said:
Ryan Mavin that's a very comprehensive list. I find it difficult to believe that anyone would ever actually populate all those usefully.
And to demonstrate that I'm just as guilty, there's nothing there about independence skills, which is very important for aged patients
Agreed, my take away of the different emphasis in Rural and Remote areas as compared to the usual city locations, the ranking of what they see as most important (where we would get the most bang for our buck) and ideally where along the patient journey we can capture this so the consumer only has to tell us one.
Actually, most of those squarely fit in the SDOH space, but not all of them are currently on the SDOH table. Are you talking to that project?
What happened to the idea of an IPS being a general purpose summary? Have we given up on it being a limited focused document of the headlines for emergency care? Anyhow...
Several of those categories also fall within the PACIO PFE (personal functioning and engagement) and TOC (transitions of care) scope. It would be nice if there was international participation on those to move their scope beyond the US.
IPS is a good base for derivations that serve requirements more specific than the original 'unplanned cross-border care' use case. In NZ we're talking about using it as replacement for GP2GP (complete patient primary care record transfers) but that would require constraints on the original requirement ('give us everything') as well as addressing the question raised in the title of this thread.
I think it is hard to define "top down" what a summary should consist of, given the variety of purposes to which it might be put. IPS is a great container. How it is filled should be up to the person requesting it, given constraints of those providing data for the summary... For instance, if I want to create a summary with two years of lab data and five years of diagnoses, but the EHR instance I'm querying has only the last year's data, then I should know that the data I'm getting is less than I've requested. Similarly, if I request two years of lab data from a source that had a decade's worth, I should only receive two years.
That transparency in what I get, and how much of it, means more to me than a predefined list of resource types that comprise an overarching view of a "general summary for all purposes".
Bill Lober said:
For instance, if I want to create a summary with two years of lab data and five years of diagnoses, but the EHR instance I'm querying has only the last year's data, then I should know that the data I'm getting is less than I've requested.
In terms of the depth of data, date filters alone might not be sufficient. Records that are marked as relevant to a patient's current health & wellness would be more useful.
From a breadth perspective, it also might be useful to see which elements are common between the various national CDI specifications (US, AU, CA, NZ, etc.). Certainly to analyse what's still missing in the core IPS IG (e.g. clinical notes from encounters).
Peter Jordan said:
In terms of the depth of data, date filters alone might not be sufficient. Records that are marked as relevant to a patient's current health & wellness would be more useful.
I agree re relevance! It seems to me that filtering (and understanding what happened when the source applied those filters) is kind of mechanical, whereas marking records (resources?) as relevant to a patient's current health and wellness would definitely be more useful - but labor-intensive and requiring some clinical judgement?
maybe I'm not giving enough credit to the possibilities of an LLM-based determination of relevancy for a particular individual and a particular intended use - after all, this is the miracle age!
or maybe it's too late at night for clear thinking...!
Are we still observing the difference between a) IPS, b) a FHIR document, and c) FHIR data?
Jose Costa Teixeira said:
Are we still observing the difference between a) IPS, b) a FHIR document, and c) FHIR data?
I'm not entirely sure what you mean (e.g. 'honouring' rather than 'observing'?), but this discussion is about content and could apply equally to the CDA representation of IPS.
yes, respecting / being aware of.
I see the discussion is about content but I think there is content that may be more appropriate to put outside of the IPS
Jose Costa Teixeira said:
I think there is content that may be more appropriate to put outside of the IPS
For sure - but the question being raised here is "what content". The basic use case for IPS is here but this is clearly being expanded by national derivations fed by local requirements.
sure, but national derivations may hink twice before making IPS the way to exchange any data any time.
i mean, IPS is not meant to be the representation of the EHR. It is an agreed subset. National patient summaries should not append IPS until there's a full EHR in there
(this is my opinion and justification for my point above).
If a national derivation says their IPS may include 2 years of data, not 6 months - that is fine.
we won't have an agreement of what is the best time window. and that is ok
but if we say we should add Tasks for the detailed execution of a procedure, or scheduling,... these are not "Summary" so I don't see the point in containing those in the IPS
Indeed - but the IPS IG is an extremely useful starting base. Certainly NZ implementers see it as an excellent candidate for replacing GP2GP (entire primary care record data transfers). Data filtering is required in that system - 12 years of implementation experience (using CDA) has certainly taught us that!
starting base for document-only data exchange - sure. But there's more than documents.
and there are other documents beyond IPS
and there should be
Documents as in a FHIR Composition - and/or Clinical Documents such as scanned documents and images?
documents as a composition. Much (most) of the data may be best transmited in REST, depending on the setting. Or messages if we want
most of that data doesn't need an authored, consistent, subsetted representation.
(but I think that has been largely discussed and agreed by now, so sorry if I am repeating it, it's just that that I am always concerned that IPS becomes the only envelope for sending any and all health data.)
Hello folks,
In Canada, we have a couple of implementations that have worked with their clinical working groups to determine how much content to include in their patient summary (PS). Please note that some jurisdictions are not putting filters on the data in their first limited product rollout (LPR) releases. They may re-visit this after their LPR learnings are collected. Here is a summary of what we know so far:
Medication Summary
Jurisdiction 1:
To be included in the PS:
· Only include prescriptions that are not considered to be inactive, expired or closed
· If duplicate prescriptions exist where Medication Name, Medication Dosage and Medication Frequency are the same, filter out all but the most recent
· Only include prescriptions written within 18 months prior to the current date when the EMR scheduled process is running
· Do not include prescriptions with no date or no name
To be grouped/sorted by:
· By medication name (alphabetically), and then by Prescription Written Date, with most recent date first"
Jurisdiction 2:
To be included in the PS:
· Last 15 months of prescribed medications,
To be sorted by:
· most recent date
Allergies/Intolerances
To be included in PS:
· Include all
To be grouped/sorted by:
· Drug codes grouping first, followed by group without drug code
Problems
To be included in PS:
• Conditions and diagnoses with no resolved date or where resolved date is no more than 11 years prior to the current date.
To be grouped/sorted by:
• Sorted by Active or current first followed by other statuses.
History of Procedures
To be included in PS:
• Include all
To be sorted by:
• By date with most recent first, in descending order. Partial dates are sorted as though they are as early as possible (e.g. 2019-01 is treated as earlier than 2019-01-20 and later than 2018-06-17). Blank dates appear last.
Vital Signs
To be included in PS:
· Include last six (6) dates that contain at least one (1) vital measurement. For each of those dates, include the last recorded vital measurement for each vital element.
To be sorted by:
· By date with most recent first, in descending order.
Immunizations
To be included in PS:
· Available publicly funded immunizations
To be sorted by:
· Most recent received date
Results:
Lab Results: Last 12 months of laboratory tests, sorted by recent test collection date.
Imaging Reports: Last 12 months of medical imaging tests, sorted by most recent imaging test date.
Elliot Silver said:
What happened to the idea of an IPS being a general purpose summary? Have we given up on it being a limited focused document of the headlines for emergency care? Anyhow...
Several of those categories also fall within the PACIO PFE (personal functioning and engagement) and TOC (transitions of care) scope. It would be nice if there was international participation on those to move their scope beyond the US.
Maybe this comment is useful in the context of the discussion of different summary types... Seems like I've been having verbal conversations about this with different folks several times today!
Using TOC scope as an example of a type of summary, I think the diagram at this link lays out the TOC scope pretty nicely. (at least I've found it pretty helpful, though I'd be the first to say I lack a detailed understanding...)
https://paciowg.github.io/transitions-of-care-fsh/guidance.html
@Ravi Kafle and I were talking about this again today, so I figured I'd drag him in!
When I look at the _categories_ of information on the TOC diagram, the (well thought out) utility for transitions is clear to me. It seems like many of those categories are also part of IPS (and other composition-based summaries - eCR, etc.). There are a few areas that don't overlap, but doesn't it seem that a specific patient's summary could satisfy both some near-future version of TOC scope _and_ some near-future version of IPS? (especially if the underlying ISO spec to which I hear @John D'Amore and @Rob Hausam refer continues to evolve?)
If the content for different use cases overlaps, then wouldn't it make sense that a particular document built from that information might be useful for more than one use case? That's a little different than saying a particular document _is_ an IPS or _is_ a TOC, but rather that it could meet requirement _for use as_ an IPS, or as a TOC document.
I'm probably misusing the terms a bit, but when there are so many different variations of "the right information" for a particular use case, it seems useful to have a shorthand to talk about meeting one or more use cases, rather than a shorthand that says this document is one type _or_ another type.
@Allana Cameron has described an effort to understand commonalities in Canadian and provincial PSs. And maybe it's OK for the summary in one location to vary from the summary in another, just as a summary for one use might differ from that for another use. Yet a summary _could_ be sufficient to meet the requirements for more than one location, or more than one use.
Hi Everyone,
In Australia, as part of Sparked, our FHIR accelerator, we have recently been looking at the IPS and patient summary and asked our clinical design group in a workshop of ~120 people, what they thought should be included in a patient summary as a first cut - considering feasibility, their own use cases, that this would be an iterative process, noting that at a minimum we should include the Required elements from IPS and they voted for the following
We are working through the next level of detail to include in our AUCDI Release 2
Jose Costa Teixeira said:
Are we still observing the difference between a) IPS, b) a FHIR document, and c) FHIR data?
and d) $summary. The IPS is extensible and it would be strange to forbid content, but $summary is just the currently defined IPS content
$summary is a) Summary
I don't see the difference.
IPS is not forbidding content. It is a selection of agreed content
If I unilaterally extend, I am outside of the agreed content
and that should not forbidden, is just my own flavour of IPS where others may not understand my extras
and there may be options to exchange that data other than an IPS - other FHIR documents or just RESTful exchange of FHIR resources.
In the Netherlands our national PS (BgZ) contains:
For labs, medication we use history of 4 months, items such as problems are either active or flagged as potentially still of concern in the EHR, and only exchanged if flagged or active
It seems like some options to $summary to shape the query will be helpful, and also some way of the server conveying constraints it may have had in fulfilling the request (time period, data completeness, confidentiality restrictions, etc.,).
This seems like a problem that could have a wide variety of intricate solutions (a disaster!), but those who know FHIR better than I do might be able to point to an approach, particularly to the idea the server conveying back it's constraints with the data. That would be helpful even if the $summary operation had no query options.
i think that is technically doable
I think it will be a good idea to have the IPS document be able to convey the selection criteria that were used in creating it (likely as a separate statement for each section). One of the challenges, though, will be if we can identify or create a standard way that can be used to express those selection criteria (it would at the least be sub-optimal for this to be done via non-standard text or various differing syntaxes).
Bill Lober said:
It seems like some options to $summary to shape the query will be helpful, and also some way of the server conveying constraints it may have had in fulfilling the request (time period, data completeness, confidentiality restrictions, etc.,).
This seems like a problem that could have a wide variety of intricate solutions (a disaster!), but those who know FHIR better than I do might be able to point to an approach, particularly to the idea the server conveying back it's constraints with the data. That would be helpful even if the $summary operation had no query options.
I agree with you, there should be a mechanism to indicate what rules need to be applied for a particular summary. Maybe the selection is configurable at the "big" solution level (e.g. HIE decides the rules) or perhaps determined by the user type (e.g. patient vs health professional(s)), amongst other options?
In terms of "relevance" rules, has anyone thought of special clinical terms that, if available in the longitudinal patient record, should be called out in the patient summary?
Looking at procedures, for example, there might be some very old surgeries that time base rules would discard, but they would still be very important to know for a new carer/emergency doctor (e.g. appendix removed). Another area where I could see this been beneficial is medicines. This section is most likely to go through date filtering, having possibly a large volume of patient records. There might be medicine codes/class that are important to know as administered even if it was a long time ago.
I can't find any other updates - is there support for ICD-11 in the tooling yet?
If not, should we make a "terminology" IG that contains a subset of ICD-11 so that the VS expansion works?
What would be the ideal way to have this (maybe I can do some work there)?
@Grahame Grieve @Carl Leitner @Ritika Rawlani
ICD-11 is not supported yet. I've been meaning to chase this up with WHO
it's on my backlog
so, meanwhile, should we add a ICD-11 codesystem to a new/temporary terminology IG as a dependency?
no I don't think you should. very much not, for licensing reasons, but it's also a complex code system
flagging for @Joe Amlung and @Jonathan Payne . The expansion would be needed for a WHO IG.
really, I need to talk to Robert Jakub and/or Can Celic
first target is for the digital ICVP (yellow book). We can put it needed codes in a WHO IG as a stop-gap to allow resolution of vaccine codes and then transition to proper TS support later (via OCL/ICD-API)
I will flag technical bits for Can and team....
if it's a WHO IG, you can do what you want with regard to licensing. None of the rest of us can do that (I still don't think we can actually use ICD-11)
Yeah, not worried on the licensing bit. As a stop gap, we can add in the ICD11 codes that we need for now in code system resource, but longer term to do it the right way. Something like this that would put in a "WHO TS" IG:
https://smart.who.int/ddcc/CodeSystem-DDCC-ICD11-CodeSystem.html
This will technically make the valueset expansion work, but is not something we want to keep up.
I think that what is needed to be done is in the common WHO/HL7 workplan for OCL, but maybe I misunderstood something. I haven't yet dived into the details on what the exact requirement that the IG Publisher has to support the expansion.
we need a terminology service that supports ICD-11. WHO intend to provide one, but it needs to meet our technical requirements, and I haven't heard that it will. And it appears that the licensing restrictions mean that I can't put it on tx.fhir.org. So I don't know where that leaves us
what are the technical requirements specifically. i know there is some discussion around packaging but not sure this is the same
for the licensing restrictions on tx.fhir.org, can HL7 send something more formally around the concerns including me and Nat?
(i think it was related to redistribution / commercial use)
Open ICD-11 license (distributed under Creative Commons Attribution-NoDerivs 3.0 IGO license)
1.2.2.WHO does not consider incorporation of ICD-11 into a software product to be an “adaptation”, provided that you do not do any of the following:
- Reproduce ICD-11 in part or whole and distribute it under a different name or without attribution;
- Reproduce and distribute ICD-11 in part or whole without the ICD-11 codes;
- Reproduce ICD-11 in part or a whole without the ICD-11 URIs; or
- Reproduce and distribute ICD-11, in part or whole, with any combination of a-c above.
Does this or does this not allow producing a FHIR CodeSystem representation of ICD11? This is the key sticking point for us being able to support it.
What about previous versions of ICD?
They are licensed differently
:thinking:
@Michael Lawley we could make the uri a property of the code system, and distribute it that way. So I didn't think that the code system representation was really the issue
okay, then as long as a FHIR CodeSystem representation doesn't fall foul of:
- 1.2.1.To prevent the dilution of ICD’s purpose to provide a definitive standard for identifying health information, neither the Licensed Materials, nor any portion thereof, may be used for the purpose of developing or promulgating a different standard.
we should be okay, and then we need to work out how to identify Foundation vs any of the Linnearizations.
I am finding some strange things in WHO IGs and elsewhere:
THO has a content "not-present" version of http://id.who.int/icd/release/11/mms also with no hierarchyMeaning
then we need to work out how to identify Foundation vs any of the Linnearizations.
we've already agreed on the fundamentals with regard to that, and the WHO public API includes a FHIR API that expresses those agreements
I have been scouring https://icd.who.int/icdapi and cannot find FHIR anything
As per Jose Teixeira, who I asked a months or so ago about incomplete icd-11 code systems in WHO FHIR implementation guides: these are just minimal placeholders (effectively a join of value sets required by a FHIR IG, promoted to a code system) whilst awaiting the full thing.
@Grahame Grieve do you know of any plans from WHO/ICD also having ICD-10 hosted on that same service?
I have no information about that. but which ICD-10?
ICD-10-WHO and ICD-10-DK
@Michael Lawley @Grahame Grieve you're most welcome to look at the ICD-11 MMS Code System on Terminz and tell me if this exemplar is valid and legal. It uses the MMS linearization distribution and looks up the Foundation Properties using an API Key obtained from the WHO (the linearization distribution lacks additional designations and properties).
I tried a simple lookup on the WHO prerelease endpoint:
https://icdapi-fhir-prerelease.azurewebsites.net/fhir/CodeSystem/$lookup?code=XM68M6&system=http://id.who.int/icd/release/11/mms
{
"resourceType": "Parameters",
"parameter": [
{
"name": "name",
"valueString": "ICD-11 for Mortality and Morbidity Statistics"
},
{
"name": "version",
"valueString": "2024-01"
},
{
"name": "display",
"valueString": "COVID-19 vaccines"
},
{
"name": "property",
"part": [
{
"name": "code",
"valueCode": "id"
},
{
"name": "value",
"valueCode": "http://id.who.int/icd/release/11/2024-01/mms/894585096"
}
]
},
{
"name": "property",
"part": [
{
"name": "code",
"valueCode": "parent"
},
{
"name": "value",
"valueCode": "http://id.who.int/icd/release/11/2024-01/mms/1347156717"
}
]
},
...
That's interesting - the code "XM68M6" has a parent with value "http://id.who.int/icd/release/11/2024-01/mms/1347156717"
If I then do a lookup of this code I get:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "name",
"valueString": "ICD-11 for Mortality and Morbidity Statistics"
},
{
"name": "version",
"valueString": "2024-01"
},
{
"name": "display",
"valueString": "Viral vaccines"
},
{
"name": "property",
"part": [
{
"name": "code",
"valueCode": "id"
},
{
"name": "value",
"valueCode": "http://id.who.int/icd/release/11/2024-01/mms/1347156717"
}
]
},
{
"name": "property",
"part": [
{
"name": "code",
"valueCode": "code"
},
{
"name": "value",
"valueCode": "XM61M7"
}
]
},
...
so it looks like "XM61M7" and "http://id.who.int/icd/release/11/2024-01/mms/1347156717" are treated as equivalent in some way.
But then if I $lookup at their parent: "http://id.who.int/icd/release/11/2024-01/mms/164949870" I get
{
"resourceType": "Parameters",
"parameter": [
{
"name": "name",
"valueString": "ICD-11 for Mortality and Morbidity Statistics"
},
{
"name": "version",
"valueString": "2024-01"
},
{
"name": "display",
"valueString": "Vaccines"
},
{
"name": "property",
"part": [
{
"name": "code",
"valueCode": "id"
},
{
"name": "value",
"valueCode": "http://id.who.int/icd/release/11/2024-01/mms/164949870"
}
]
},
{
"name": "property",
"part": [
{
"name": "code",
"valueCode": "code"
},
{
"name": "value",
"valueCode": ""
}
]
},
...
the code is an empty string?
@Peter Jordan your code system is "not-present"?
I can at least say that it should be flagged as caseSensitive=true
Doing a $lookup as per above, only gives back minimal information; is there a way to pull back the hierarchy?
Michael Lawley said:
Peter Jordan your code system is "not-present"?
I can at least say that it should be flagged as caseSensitive=true
Doing a $lookup as per above, only gives back minimal information; is there a way to pull back the hierarchy?
Wouldn't you expect the value of CodeSystem.content to be "non-present"?
I'll update the caseSensitive value to "true"
Try this to see some nascent Code System properties (grabbed from the Foundation) - including parent and child...
I haven't tried anything trickier, such as $subsumes - that could involve a lot of API calls to the Foundation!
Ah, I'll give that a go - I had tried property=parent to no avail
Yeah - I haven't implemented $lookup requests for individual properties yet - just all.
@Peter Jordan Is there a way to do $lookup for the Foundation entity that was missing the code (mentioned above) i.e. so I guess something like (gives me "Code System not found"):
https://terminz.azurewebsites.net/fhir/CodeSystem/$lookup?system=http://id.who.int/icd/entity&code=http://id.who.int/icd/entity/164949870&property=*&_format=json&_summary=data
@Kari Heinonen my server won't recognize that system uri - i.e. I don't have a CodeSystem resource that represents the ICD-11 Foundation and, last time I looked, it's not available to download.
And you don't treat the URIs like http://id.who.int/icd/release/11/2024-01/mms/164949870 as codes in the MMS?
@Kari Heinonen I think the main issue is that the MMS (linearization) doesn't have a parent code in that case.
I think this is one of the things yet to be sorted out regarding representing the MMS as a FHIR CodeSystem
OK, thank you, thought it must be something like that. Just being overly curious to what that "entity without code" looks like since the interactive ICD-11 browser seems to be aware of that hierarchy relation.
@Daniel Vreeman fyi
thanks all for the discussion and clarificiation. i am following up. hopefully we can clarify the valueset issue.
Wondering how to interpret Substance.instance
-- which is defined as "Is this an instance of a substance or a kind of one". I thought documenting a kind of a FHIR instance is what profiles are for?
hi Brian,
When the value is "instance" it means that this resource data (which could also be called a resource instance, but that is an unhelpful coincidence) represents an actual substance entity, that exists in the real world and could be touched (probably) e.g. an actual lump of sugar.
Alternatively it is a type (kind) of substance e.g. the concept of sugar.
Of which you could then have instances.
So kind means this resource (instance) is the wikipedia page about sugar. Sugar info.
Instance means this resource (instance) is about some sugar. Actual sugar.
Profiles are nice computable way to say how you want your "instances" of any resource to look. I suppose there are instances of resources (data), and kinds of resources (as in the FHIR spec), and then there are instances of substances (lumps etc.) and kinds of substances (types, definitions).
But wouldn't the concept of sugar be represented as a profile (which is an instance of a structure definition :)) where the code is set to mean sugar? Also noteworthy that as far as I am aware, this flag does not appear on other resource types (including Medication).
I bring this up because I am just noticing this was changed in R5.
We use profiles to describe how we want our instances to look (e.g. the concept of blood pressure is a profile, and the actual reading is an instance of Observation that conforms to that profile), and we also use R4 Substance + profiles. This new pattern of a boolean to modify the nature of the resource seems different than how it is handled in the rest of FHIR.
Only if you want to specify how a single resource should be in a profile. Sugar is one of a million substances. You don't want a profile for all of them, any more than you would have a profile of for patient John Smith. If there were 100 variations of Sugar, then you may want a "sugar substances profile", so that all varieties of sugar are done similarly, eg using the "international classification of sugar codes". But otherwise it doesn't make sense to have a profile for one single resource instance
You could have a profile of BP, it is true, because that is very common, and there are only 20 or so vital signs and we want all the millions of instances to all look the same. But equally, we don't have a profile for every clinical condition in the world (all the hundreds of thousands of SCT codes).
If you have lots of people making sugar instances and there is something special about them that differs from how salt is represented, then sure, make a profile. Bit this is a totally different issue to Substance.instance. They are not the same concept at all.
Profiles add documentation, essentially. Substance.instance is a property of the data, that tells people what sort of thing it refers to (like Patient.gender). It is nothing to do with profiles.
Okay. I am still not seeing how they are different. Or why this pattern then would not apply to Medication. Also, in CPG we use Structure Definitions as first class resources, not just documentation (Case Feature Definitions).
I think the same thing was considered for Medication, but it just didnt make it to be an actual property.
To be consistent, Medication could have one. We were doing some revision on Substance, and at that time the instance vs kind was being discussed and it seemed good to make it explicit. That didn't happen with Medication, but it could have.
Then also for Specimen, Body Structure, Claim, etc. they would all need this boolean right?
These 2 resources are the only ones that I can think of that can be both instances or kinds.
No because there is e.g. SpecimenDefinition
For some resources they can only be instances, and a different resource does the work of the definition. Substance (and Medication) are unusual in that respect.
Medication is somewhat different to Substance too. Medication can be stated at various levels of completeness. But I think using it as a true "definition" is less common, and not really needed. Because drugs tend to be defined by code systems (RxNorm etc), not resources.
And there is no perceived need for BodyStructure definition. there is only one body, I guess, and the medical knowledge about say, livers, is not typically captured in FHIR. That would be in the literature.
Substances are more of a changeable thing, and have electronic catalogues, with supporting data about each substance. You don't tend to get electronic catalogues of body part, except in terminology.
You could have Claim definitions I suppose. But who is making processable electronic definitions of claim types?
The point I was making is structure definitions allow us to define the definitions of types of resources already. I am still not seeing the need for that boolean, but will think about it more.
This is not meta data about a resource - which is what SD is for. This is perhaps meta data about a resource instance.
There is a clear distinction in the use. It is not possible to do the job of Substance.instance with a profile.
All an SD can do is say how to use the resource. This would be like trying to use a profile to say if an individual patient was male. Can't be done. Saying how male patients are represented can be done. Saying if a patient is male cannot be done.
Defining the concept of sugar can be done in a structure definition. Definition a real pile of sugar can be done with an instance of Substance that conforms to that profile?
Again, that's the approach we use in CPG (case feature definitions are structure definitions)
But you cannot change from a kind to an instance using a profile. Any more than a profile can flip male to female.
You could define a new whole resource using an SD e.g. SubstanceInstance, but that is not FHIR. Basically put the instance flag into the name of the resource.
A resource type can have resource instances. Maybe that is what you are thinking. But this is not that concept.
The phrase "definition of a real pile" is a little strange though. It would be an instance of a real pile. We don't tend to say "a definition of a patient John Smith".
By analogy with Patient, if there was a Patient.instance flag, set to type "kind" it might be used to define, say what "US citizens" were like. You could then make a FHIR data set of different nationalities, as actual FHIR resources, saying what the postal address would be (an address in the US probably).
It is true that you could do the same thing with FHIR profiles (and we do e.g. US Core).
But FHIR profiles are not user editable data. Substance catalogues are sets of user editable data about kinds of substances. New ones come along all the time. Users can add new substances to the catalogue.
But users cannot add a new type of patient. They cannot add "Tuvalu citizen". That can only be done as a profile, by standards makers, not by users.
Maybe that is where the similarity and confusion is.
Admittedly you could in theory use StructureDefinitions as end-user editable definitions and let users create new nationality profiles as FHIR instances. Then drive validation off those. FHIR does eat its own dogfood, so resource profiles are already resources.
But because national profiles are relative static, and more sophisticated, we (certain people) do this "offline" using profile tools and repositories.
Substance catalogues are not static though, and are meant to be end user edited. So they are good for being represented in (end-)user data, not profiles.
So FHIR does definitions in two ways I suppose, as resources (usually with a whole separate resource e.g. SpecimenDefinition, PlanDefinition etc, but not always - regrettably I would say), and as StructureDefinitions/profiles.
It was originally, methodologically, thought that having two resource "flavours" was overkill, I think. Later the paradigm of having both {Resource} and {Resource}Definition seemed to take hold e.g. ObservationDefinition is a relative newcomer. And exists even though we have plenty of BP profiles...
I agree there is tension/overlap/confusion between the patterns of (resourceType)Definition and Structure Definition. And as you said these definition resource types are a relative newcomer. But now this boolean for instance seem an even newer newcomer and now a third pattern to consider.
You could have a catalog of StructureDefinitions about Observations -- or a catalog of ObservationDefintions (same with SubstanceDefinitions or SDs about Substance). You could also have tools to make managing a catalog of SDs accessible, since structure definitions are data, and there is nothing in FHIR spec that restricts what kind of end-user can create structure definitions.
I did not have an assumption that certain resource types are off limits for users in the FHIR specification. In clinical reasoning, we create structure definitions as part of routine authoring, with tooling support, even though many of the teams we work with are not federal agencies. I am not sure the level of sophistication we have, but they are kinda sophisticated :)
It's not really all that new. This flag has around since the early days of R5. Almost 5 years. But the resource has had this feature since DSTU2 (and had an optional backbone about it). It could always be a kind or an instance. It just was not so explicit til R5.
Sure, some end users can create profiles. Nothing is off limits, no hard edges. Some create complex quality measures and plan definitions. But a list of substances with a few properties is sort of in a different category I suppose. They are not deeply FHIR oriented, unlike say a profile (though complexity can indeed be hidden).
Profiles are "FHIR like", they are about data constraints. Substance types are very much in user space (chemists).
I think one thing that is missing from this discussion is that whether an instance claims conformance to a profile or whether it is conformant to a profile, doesn't change the meaning of the resource. A Patient resource that meets the Tuvalu patient profile doesn't need to shout can do so without adding the claim that it meets that profile. And if it does claim that profile, it can't change the meaning of the resource.
The other thing is that profiles (realized in StructureDefinitions) can't be used most places that a Substance can be used. I can't just plop the sugar profile in somewhere that I want to say "use Dememera." Those places are looking for a Substance.
I think it is valid to say that if a Patient is conformant to US Core, it means it is a US Core Patient. And if an Observation conforms to blood pressure profile, that Observation means a blood pressure. In this sense, the structure definition uses conformance rules to express meaning, and the Patient or Observation are the instances of it.
I think you can make reference to a sugar profile by either an invariant rule or using the artifact-reference extension (as seen in CRMI, and the FHIR extension pack).
E.g. those places can be expressed as referring to a substance that means Sugar
But in R6 with SubstanceDefinition I am guessing the Substance.instance bool will go away? In this case the substance of sugar will be via SubstanceDefinition, and the case of a pile of sugar it will be Substance with instantiates[x] to that definition?
That is a possible way to do this. But SubstanceDefinition was not intended to totally replace Substance[instance=kind]. Personally I would quite like that, but the thinking was that for simpler and legacy systems that are using Substance for that already, they can keep doing that. SubstanceDefinition is for serious catalogues that need a lot of info. Substance is still there for simpler cases. I actually doubt that anyone is using Substance for that, but you never know. We already had a presumed legacy when the bigger requirements that led to SubstanceDefinition came along. We didn't want to fill up Substance with all the stuff in SubstanceDefinition, but some use cases do need it. So we have two worlds. I would consider deprecating Substance.instance, and making it always an instance. But it may break someone somewhere and stop them going to R6, without API level changes.
Brian Kaney said:
I think it is valid to say that if a Patient is conformant to US Core, it means it is a US Core Patient.
I like to think of a profile as one of those children's block toys, where you have various shaped blocks and various shaped holes to push them through. If an instance conforms to a profile, it meets all the constraints of the profile. If a block can go through the hole, it meets the constraints of the hole. Just because I can slide the cylinder though the square hole doesn't mean you can start calling it a cube.
Rik Smithies said:
Personally I would quite like that, but the thinking was that for simpler and legacy systems that are using Substance for that already, they can keep doing that.
Substance.instance data type changed drastically from R4 -> R5. Since practically speaking many are skipping 5 and will be going right to 6, it could be a good idea to remove that boolean in R6..
Elliot Silver said:
Just because I can slide the cylinder though the square hole doesn't mean you can start calling it a cube.
Sure you can ;) given the context of use - but if you care about the shape than your conformance would need to define it -- "a small cylinder means it fits in a hole" vs "a small cylinder means it fits in a hole, and that hole is round, and the edges of the cylinder are all equidistant from the hole edge".
re removing the flag, that would break any R4 data that used this resource for kinds of Substance. So while it may be good for some, it could be very bad for others. What's the big problem with the flag anyway?
In R4 https://hl7.org/fhir/r4/substance.html Substance.instance
is a complex type:
Yes indeed. It's definitely a change. Is it hard to support do you think? Is it the fact that it's changed from a backbone to a plain attribute? Or is it that the concept of instance is not right for you.
Here are my thoughts:
instance
it is a complex type, and the Substance resource type has dual role and could be either an instance or class. Substance.instance
remains and the data type changed. I would have expected to simply remove this property. I think it is confusing to support this property when I consider a migration from R4 -> R5 (it seems http://hl7.org/fhir/extensions/conversions-Substance.html is not valid). Here's my thoughts on how to migrate:
instance = true
I don't see a case where (r5) Substance.instance would ever be false, since that's what SubstanceDefinition is for.
In continuing research there seem to be inconsistently documented semantics and missing relationships that I would have expected to exist:
Resource Type | Def Resource Type | Semantics | Relationships |
---|---|---|---|
Observation | ObservationDefinition | Defined | Observation.instantiates[x] |
Condition | ConditionDefinition | Not Defined | N/A |
Medication | MedicationKnowledge | Not Defined | Medication.definition |
Substance | SubstanceDefinition | Not Defined | N/A |
Device | DeviceDefinition | Not Defined | Device.definition |
Some discussion in O&O yesterday. There is a growing feeling that it may be good to deprecate Substance as a definition. The main use of this is by Pharmacy WG for medication that is defined specially, using Medication.ingredient (which is relatively rare) but then not using a substance code, but a reference to Substance resource. That now appears to be vanishingly rare. It needs some discussion O&O, Pharmacy and BR&R to work this out. Co-chairs are aware.
Hi @Grahame Grieve ,
The Netherlands now has a nice national terminology server (the Ontoserver)! We would like to use it for validation purposes as this would solve a lot of validator errors/warnings due to the Dutch SNOMED extension sets we use.
However, to use the Ontoserver we require authentication based on bearer tokens. I believe the HL7 validator currently does not support authentication? Are there any plans to add such a feature?
"HL7 Validator" also means "IG Publisher" in this context ;)
@Mark Iantorno please add this to your list. and I would propose:
Okay, this will fit in with the other HTTP library work I want to do
Nice! :D Thanks
+1 for this request , ie. hl7validator to support OAuth2 over HTTPS against a 3rd-party FHIR TX instance
supply the OAuth2 access token to the hl7validator - assuming it is obtained out-of-band in one of the OAuth2 flows
@Mark Iantorno @Grahame Grieve
The core validator does token based auth as of now
OAuth2 would be a little more difficult to set up
Mark Iantorno said:
The core validator does token based auth as of now
Can you elaborate a bit more, please, what that means, or where documented? Glad to test drive!
(I did not see it under https://github.com/hapifhir/org.hl7.fhir.core )
If it means, supply the hl7validator CLI with an OAuth2 Bearer access token, obtained separately (out-of-band), like "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", and using it in the FHIR-REST calls to the TX, even without refresh, in the HTTP Authorization request header, that'd be great already!
@Mark Iantorno - is there a feature branch we can look at / contribute to?
PS: are you our sick? get well soon!
I was sick last week, feeling better now, thanks.
that one is for the website that hosts the validator
actual validator is in the core library
@David Simons
Thanks and yes - I scrutinized that latter repo - but could not find any use of the headers
argument in the org.hl7.fhir.core\org.hl7.fhir.r4\src\main\java\org\hl7\fhir\r4\utils\client\ClientUtils.java
, yet, for example, trickling down from the
org.hl7.fhir.validation\src\main\java\org\hl7\fhir\validation\cli\utils\Params.java
public <T extends Resource> ResourceRequest<T> issuePostRequest(URI resourceUri,
byte[] payload,
String resourceFormat,
Headers headers,
String message,
long timeout)
e.g. a public static final String TERMINOLOGY_AUTH = "-txAuth";
for a bearer token to be ingested as a HTTP Authorization request header. :)
created a DRAFT pull request https://github.com/hapifhir/org.hl7.fhir.core/pull/566/files - let me see how far I get myself :)
was able to get the OAuth2 Bearer access token to be passed to TX, from CLI via parameter like-txAccessToken e5f81bb4-4cb8-47a7-9ee4-03b049dacbbb
, on that branch/PR.
Now trying to overcome (customizing):
metadata?_summary=true
, and metadata?mode=terminology
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated. Make sure to release the connection before allocating another one
in the R4 ClientUtils on the httpclient.execute(request). This is probably related to the required work on the HTTP client in the hl7validator.Hopefully this work item to productize can be prioritized :) https://github.com/hapifhir/org.hl7.fhir.core/issues/588
@Mark Iantorno yes but we need to get a new version out asap
working on this today
@Grahame Grieve do you mean you want me to publish a new version of the core before doing this
or just do this, then publish a new version of the core?
well, I'd really like to have you sort out your merge thing, then I can commit a bunch of code, and then we get a release out later today your time
All my merges accept for the one I need James to assist with are closed?
Which one do you mean?
The validation one you said you had to merge with the code I committed on Friday
I pushed the changes the PR you had made
and merged that
ok. I'll merge when I wake up tomorrow and we'll do a release
sounds goood
I'll start on the issue 588
Did this (ability to supply bearer token via the CLI) ever properly land? I followed the tickets and got to https://github.com/hapifhir/org.hl7.fhir.core/issues/603 but that was auto-closed due to inactivity.
I think it's close. All the infrastructure is in place, but no one wanted to test it for us
I have NHS people wanting this capability
well, you could consider doing a PR.
Roughly, org.hl7.fhir.convertors.txClient.TerminologyClientFactory.makeClient needs to take a parameters with additional headers to pass through to TerminologyClientR4 etc, and that needs to be called using org.hl7.fhir.utilities.settings.FhirSettings.getApiKey
Thanks - I'll see what we can do
@Michael Lawley any positive progress you can share with us?
Totally untested, but from a quick look through the code I am thinking a patch like the following would work:
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirRequestBuilder.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/network/FhirRequestBuilder.java
@@ -27,6 +27,7 @@ public class FhirRequestBuilder {
protected static final String HTTP_PROXY_USER = "http.proxyUser";
protected static final String HTTP_PROXY_PASS = "http.proxyPassword";
protected static final String HEADER_PROXY_AUTH = "Proxy-Authorization";
+ protected static final String HEADER_AUTHORIZATION = "Authorization";
protected static final String LOCATION_HEADER = "location";
protected static final String CONTENT_LOCATION_HEADER = "content-location";
protected static final String DEFAULT_CHARSET = "UTF-8";
@@ -184,6 +185,11 @@ public class FhirRequestBuilder {
return response.request().newBuilder()
.header(HEADER_PROXY_AUTH, credential)
.build();
+ } else if (FhirSettings.hasApiKey()) {
+ String credential = FhirSettings.getApiKey();
+ return response.request().newBuilder()
+ .header(HEADER_AUTHORIZATION, "Bearer: " + credential)
+ .build();
}
return response.request().newBuilder().build();
};
@David Otasek can you look at this - thanks
Is it possible to propose a new item control called 'dialog'? To specifically display choices in a pop up dialog.
https://hl7.org/fhir/extensions/CodeSystem-questionnaire-item-control.html
Sure, but when would you need a dialog box to display answer options for question?
For context:
It's simply a design decision, a client asked for a dialog.
And we're planning to use the 'dialog' control type in the Android FHIR SDK.
In the SDK, we have a hardcoded logic that says, if there are at least 10 options, then use a dialog. But we'd like to specifically use a dialog by declaring an item control type extension, so even if the options are less than 10, we can still use a dialog.
I would have said, if there are 10 options or more, use a drop down list, but maybe a dialog like that is right for the context of a phone app.
So, when you say "dialog", you mean specifically a dialog with checkboxes/radio buttons, and not a dialog showing a drop down list? I am just wondering if the dialog gets used for other control types sometimes.
In a phone you could make that decision anyway without having something in the item.
The UI hints are just that, and depending on the context/features/capabilities of the renderer and it's input mechanisms, those sorts of things could be done.
To me they are declaring what could be appropriate, and in some cases not appropriate.
If you're saying an auto-complete, you're giving a pretty strong indication that it's probably not going to be good to use radios...
So, when you say "dialog", you mean specifically a dialog with checkboxes/radio buttons
@Paul Lynch if options are defined, yes.
@Brian Postlethwaite
But it would also makes sense to use dialog
control type to display something else.
Let's say if we add a dialog
control type to a group, that means, whatever items are inside the group, will be displayed in a dialog. The trigger in showing that dialog can be a button.
There are an awful lot of complexities in that.
This is an example in FHIR doc where it tries to display a content to a dialog, it's not possible to do that in all renderer, since the example is not really using anything similar to dialog
control type.
https://build.fhir.org/ig/HL7/sdc/examples.html#using-contextexpression
I think defining dialog
control type would allow other renderers to specifically display a dialog in such scenario, no?
Dialogue then needs buttons, what's on them, what's the behaviour when you click them, OK, cancel, does cancel throw away the data, does that mean you need a new copy of that part. When would dynamic expressions using that data be fired etc...
I guess the question is where the line is drawn between what goes in the sdc ig and what is considered implementation. But I don't really feel dialog is a step forward in terms of "specificity" of the sdc ig - for example, we do have collapsible
which is a very specific ui treatment.
Fikri Milano said:
Brian Postlethwaite
But it would also makes sense to usedialog
control type to display something else.
Let's say if we add adialog
control type to a group, that means, whatever items are inside the group, will be displayed in a dialog. The trigger in showing that dialog can be a button.
I think the benefit in displaying options or questions in a dialog is probably specific to phone UIs, but then probably other renderers could ignore it.
One concern I have is that currently itemControl's cardinality is 0..1, which means if you said an item was 'dialog', you couldn't say anything else about it (e.g., use checkboxes or a dropdown).
@Paul Lynch would it makes sense to you if we have the dialog as it's own extension?
So in an item, we can declare both the dialog extension and itemControl extension
I don't suppose you're coming to the connectathon on the weekend by chance @Fikri Milano
I don't, how do I join?
It's an in-person event in Atlanta (USA)
I couldn't join, too expensive '-'
I thought it's an online call.
Fikri Milano said:
Paul Lynch would it makes sense to you if we have the dialog as it's own extension?
So in an item, we can declare both the dialog extension and itemControl extension
In case anyone has comment about this, please let me know
We do have online calls on Thursday afternoons (5 Eastern), but not this week or next week due to travel and the meeting next week.
Fikri Milano said:
Paul Lynch would it makes sense to you if we have the dialog as it's own extension?
So in an item, we can declare both the dialog extension and itemControl extension
Yes, that sounds better.
Lloyd McKenzie said:
We do have online calls on Thursday afternoons (5 Eastern), but not this week or next week due to travel and the meeting next week.
@Fikri Milano : https://www.hl7.org/concalls/CallDetails.cfm?concall=72728. "5 p.m. EST" should say "ET" (eastern time). It looks like you are 11 hours ahead of ET, so I can see that would be difficult time to meet for you, unfortunately.
Thanks all, it will be super early for me (4 AM), but I'll drop by if I do have the chance.
For the dialog extension, I'll create a jira ticket for now, and share the link here
Enjoy the event :D
Here's the Jira ticket https://jira.hl7.org/browse/FHIR-48350
cc @Jing Tang
It seems to me adding a 'dialog' code in the itemControl is a better solution. 'dialog' is essentially same as 'page' and 'tab-container' in that they are all containers of one or more items. They apply to the group items but not the question items.
A message was moved here from #questionnaire > Connectathon track by Ye Wang.
Yeah, that's what I initially thought, open for discussion. Feel free to leave a comment on the Jira ticket too
Dialog, to me, says "pop-up", and that's not what we're going for here...
Right, the implementation of a dialog/pop-up will be tricky. A lot of more details are needed to decide when to bring up the dialog, how to reopen the dialog once it's closed, and whether it is modal or not, etc.
And what happens if cancelled
I understand your concerns.
Would having more indicators to the extension make it more possible to add the dialog
to FHIR?
Lloyd McKenzie said:
Dialog, to me, says "pop-up", and that's not what we're going for here...
Is it because of the concerns mentioned by @Ye Wang and @Brian Postlethwaite ? Or is it something else?
If you mean you're looking to do choice items like that instead of combo boxes, you would be free to use that for your mobile interface without having specific extension to request it - outside combo-box.
But if you're looking more for sow these 5 items as a popup dialog to capture.
The item-control is the hint to indicate to the renderer what type of input mode is required to enter that field which would be most appropriate for the options.
it's not an explicit commandment that you MUST use that format.
Your rendering can be consistent with how the rest of your system does things and still retain the functionality of the form.
Usually the selection is based on how many options are available. e.g.
With mobile devices dropdown/combo can be awkward and a popup style selector which takes much of the screen is also common in other mobile forms engines.
However that style is not usually appropriate in a laptop/tablet environment.
hint to indicate to the renderer what type of input mode is required to enter that field which would be most appropriate for the options.
it's not an explicit commandment that you MUST use that format.
@Brian Postlethwaite thanks, we can say that it's optional then, depending on the renderer. The input mode would makes sense for renderer A but not renderer B.
In renderer A, the dialog
feature will be used, since it's a feature that only makes sense for renderer A.
In renderer B, the dialog
feature wouldn't be used, since it wouldn't makes sense to use it. But the questionnaire should still works ok.
With that context, do you think it would makes sense to add the dialog
extension to the specific renderer only? instead of trying to apply that to the whole FHIR standard.
I think that wouldn't affect interoperability by much, right?
So, other renderers will simply ignore that custom dialog
extension, with a note to not sacrifice functionality of the Questionnaire.
That's the expectation, but I'm sure all of us would like to explore to see if it's something we'd want to do also. And be sure if it's in the spec, we all understand the functionality.
Each of the current renderers have a few internal features that aren't in the standard, and that's ok.
But it's also good to have consistency too.
Which is also what you're seeking.
When rendering an IPS document, IPS viewers are able to do a much better job if there's a map between the section entry resources and the narrative html elements that represent it
a typical situation might be that there's a list of items, which each item in the list is associated with an underlying allergyIntolerance resource
or maybe there's a table of observations
if a renderer knew which <li> or <tr> was associated with a particular resource, it could add links, mouse-overs etc that added reference, provenance information, or it could switch displays between consumer and clinician friendly, for interest
NZ has a particular interest in this after the connectathon of the last two days. And the spec does describe how to do this in the Composition resource
<div xmlns="....">
<table class="grid">
<tr idref="t1"><td>something...</td></tr>
<tr idref="t2"><td>something else...</td></tr>
</table>
</div>
and then:
"section" : [{
"title" : "Active Problems",
"code" : {
// snip
},
"text" : {
// as above
},
"entry" : [{
"id" : "t1",
"reference" : "Condition/eumfh-39-07-1"
}]
},
// etc
@John D'Amore I'd like IPS to mention the pattern and have a worked example. (but not to require it; that belongs in IPS profiles)
A message was moved here from #IPS > A referencing case of a patient summary document instance in by Grahame Grieve.
@Grahame Grieve
Currently the IPS reference server uses a different pattern utilizing the narrativeLink extension to accomplish this (http://hl7.org/fhir/StructureDefinition/narrativeLink). We did it that way since that's how we read the narrative guidance around the narrativeLink and originalText extensions (https://build.fhir.org/narrative.html#linking). I agree we should incorporate examples of this into the next IPS release (note reference server was still a work in progress when 1.1 came out).
We do reference back indirectly to the base FHIR spec somewhat in this section (https://build.fhir.org/ig/HL7/fhir-ips/design.html#narrative-and-language-translation), but also agree we could clarify that further.
hmm. it's the same use case? Got an example?
I didn't use that because it's a reference from a resource to a composition, and it'll be different for each occurrance of the same resource in different IPS documents, even if the resource hasn't otherwise changed .
and because you sure don't want to update .meta.lastUpdated but you kind of need to.
the id/idref solution is neater in that it's all in the composition
through I agree it's what the spec describes more clearly
This is just a random example from the IPS reference server hosted by HL7, not necessarily a good example: https://hl7-ips-server.hl7.org/fhir/Patient/49/$summary
It does follow the pattern of placing the ID in the <tr> which is a practice used by a lot of CDA examples gong back awhile. I agree that the section.entry.id pattern looks cleaner (i.e. it's not stuck in an extension). I'll try to raise this for discussion on next IPS weekly call
Yes, let's talk about this. The next call is in just over 2 hours from now.
another reason for me to prefer the id/idref model: there might be multiple references in the narrative to the same resource (different language sections), and it's cleaner this way too
yet another: the example document you referred to has multiple matching targets for the narrativeLink extensions.
This topic was extensively discussed at the FHIR Connectathon 37. I'll tag participants in this post, but the consensus was that id/idref patterns should be the preferred mechanism for narrative linking in IPS generation. A few consequences/considerations of this decision:
THanks to those who contributed in the discussion. @Peter Jordan @Giorgio Cangioli @Rob Hausam @Darren Liu @Martin Kaye @Andrew Liu @Hanhong Lu @Abigail Nicolas @James Agnew
@Lisa Nelson this is your answer, I think
do we have an example?
Hoping to have an example in IPS before end of day today! Going to try to adapt this one https://terminz.azurewebsites.net/fhir/Patient/$summary?profile=http://hl7.org/fhir/uv/ips/StructureDefinition/Bundle-uv-ips&identifier=https://standards.digital.health.nz/ns/nhi-id|AAA1234&_format=json @Peter Jordan
ok I'll check it shortly
{
"resourceType": "Bundle",
"id": "NZ-IPS-20231009024857",
"language": "en-NZ",
"identifier": {
"system": "urn:oid:2.16.724.4.8.10.200.10",
"value": "59f51f0b-2005-485c-858e-3d3ae9657287"
},
"type": "document",
"timestamp": "2023-10-09T02:48:57.4219686+00:00",
"entry": [
{
"fullUrl": "https://terminz.azurewebsites.net/fhir/Composition/d2d5d4dd-4e86-41c6-98d2-e412882e9b4c",
"resource": {
"resourceType": "Composition",
"id": "d2d5d4dd-4e86-41c6-98d2-e412882e9b4c",
"meta": {
"versionId": "1"
},
"language": "en-NZ",
"text": {
"status": "generated",
"div": "<div xmlns='http://www.w3.org/1999/xhtml' lang='en-NZ' xml:lang='en-NZ'>International Patient Summary for <span idref=\"AAA1234\">James Judge</a></div>"
},
"identifier": {
"system": "urn:oid:2.16.840.1.113883.2.18.7.2",
"value": "59f51f0b-2005-485c-858e-3d3ae9657287"
},
"status": "final",
"type": {
"coding": [
{
"system": "http://loinc.org",
"code": "60591-5",
"display": "Patient summary Document"
}
]
},
"subject": {
"reference": "Patient/AAA1234"
},
"date": "2021-05-03",
"author": [
{
"reference": "Organization/03993b0c-87ae-478b-8556-8c52a68c3486"
}
],
"title": "International Patient Summary",
"confidentiality": "N",
"attester": [
{
"mode": "professional",
"time": "2021-05-03",
"party": {
"reference": "PractitionerRole/1153dc30-cf69-402f-9522-132ec9ec14ac"
}
}
],
"custodian": {
"reference": "Organization/15d2d767-48ba-4222-a1ca-8fa34393aed4"
},
"relatesTo": [
{
"code": "transforms",
"targetIdentifier": {
"system": "urn:oid:2.16.840.1.113883.2.18.7.2",
"value": "59f51f0b-2005-485c-858e-3d3ae9657287"
}
}
],
"event": [
{
"code": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/v3-ActClass",
"code": "PCPR"
}
]
}
],
"period": {
"end": "2021-05-03"
}
}
],
"section": [
{
"title": "Allergies and Intolerances",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "48765-2",
"display": "Allergies and adverse reactions Document"
}
]
},
"text": {
"status": "generated",
"div": "<div xmlns='http://www.w3.org/1999/xhtml' lang='en-NZ' xml:lang='en-NZ'>There is no information available regarding the subject's allergy conditions.</div>"
},
"entry": [
{
"reference": "AllergyIntolerance/d46cc177-5660-46cc-9f55-6c28e1bc3bba"
}
]
},
{
"title": "Problem List",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "11450-4",
"display": "Problem list - Reported"
}
]
},
"text": {
"status": "generated",
"div": "<div xmlns='http://www.w3.org/1999/xhtml' lang='en-NZ' xml:lang='en-NZ'>There is no information available about the subject's health problems or disabilities.</div>"
},
"entry": [
{
"reference": "Condition/20a587fa-239f-49c2-a3c8-ff2f2a18b654"
}
]
},
{
"title": "Medication Summary",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "10160-0",
"display": "History of Medication use Narrative"
}
]
},
"text": {
"status": "generated",
"div": "<div xmlns='http://www.w3.org/1999/xhtml' lang='en-NZ' xml:lang='en-NZ'>There is no information available about the subject's medication use or administration.</div>"
},
"entry": [
{
"reference": "MedicationStatement/4e348646-0375-486a-a33d-d19801e6c7f7"
}
]
},
{
"title": "Immunizations",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "11369-6",
"display": "History of Immunization Narrative"
}
]
},
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>Vaccine</th>\r\n <th>Status</th>\r\n <th>Occurance</th>\r\n <th>Route</th>\r\n <th>Dose #</th>\r\n <th>Series</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr>\r\n <td>Influenza, seasonal, injectable</td>\r\n <td>Completed</td>\r\n <td>2020-07-03</td>\r\n <td>Injection, intramuscular</td>\r\n <td>2</td>\r\n <td>45y (Eligible condition (Influenza))</td>\r\n </tr>\r\n <tr>\r\n <td>Influenza, seasonal, injectable</td>\r\n <td>Completed</td>\r\n <td>2019-06-03</td>\r\n <td>Injection, intramuscular</td>\r\n <td>1</td>\r\n <td>45y (Eligible condition (Influenza))</td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n</div>"
},
"entry": [
{
"reference": "Immunization/c5efb4c3-91cf-4f63-b176-a697215d727a"
},
{
"reference": "Immunization/f58b2627-eeac-4280-8475-195ae422aa2d"
}
]
}
]
}
},
{
"id" : "AAA1234",
"fullUrl": "https://terminz.azurewebsites.net/fhir/Patient/AAA1234",
"resource": {
"resourceType": "Patient",
"id": "AAA1234",
"text": {
"status": "generated",
"div": "<div xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-NZ'>Name: James Judge</div>"
},
"identifier": [
{
"system": "https://standards.digital.health.nz/ns/nhi-id",
"value": "AAA1234"
}
],
"name": [
{
"use": "usual",
"family": "Judge",
"given": [
"James"
]
}
],
"telecom": [
{
"system": "phone",
"value": "tel:+6478532279",
"use": "home"
}
],
"gender": "male",
"birthDate": "1985-04-25",
"address": [
{
"use": "home",
"type": "physical",
"line": [
"Bleak House",
"3 Worcester Drive",
"Rototun
Here is a link to an example using id/idref pattern adapted from @Peter Jordan server. I will go ahead and file a task for the validator to be updated since this does add a new warning since the idref is not contained in the resource which it references (but it is an the bundle) https://raw.githubusercontent.com/jddamore/IPSviewer/refs/heads/main/samples/connectathon_samples/NZ_Peter_Jordan_AAA1234.json
Discussed and JIRA tracker added here: https://jira.hl7.org/browse/FHIR-48338 @Grahame Grieve will make a task to update the validator behavior which currently returns a warning when including idref inside composition to a resource.id in the Bundle
2 example IPS instances on Terminz are now decorated (? ) with the atomic resource reference ids in the TR elements of the XHMTL narrative.
I added a test case to the validator test cases for this yesterday:
there's two links in there, one is AAA1234, which is valid. The other is AAA1234X which is not (it is a validator test case). Both are on line 23 (@Lisa Nelson )
Grahame Grieve said:
there's two links in there, one is AAA1234, which is valid. The other is AAA1234X which is not (it is a validator test case). Both are on line 23 (Lisa Nelson )
@Grahame Grieve @John D'Amore Thanks. This was just what I needed. I've got it working and even figured out a way to make the ID elements in my CDA mimic this approach nicely. But I have one concern. I don't want to have to rebuild these narrative text linking ID's when I transform the CDA document into its FHIR counterpart. Is there some way these narrative text linking id's could be a special type of identifier rather than an actual Resource id? There's no way we'll know what id the created FHIR Resource is going to have and my transformation process will be very difficult if we have to re-establish all these links with new id's in them as part of the transformation from CDA to FHIR. As the document gets moved around from place to place, the id/idref information would need to change to utilize different id's for these resources on different servers. I'd prefer to set-em and forget-em. Is there a way to make this work by referencing an identifier on the resource rather than its id?
Is there some way these narrative text linking id's could be a special type of identifier rather than an actual Resource id?
oh. it is. It refers to Bundle.entry.id, which is whatever you want it to be. I just reused the id of the resource because I'm lazy; it totally can be any valid id you want
Grahame Grieve said:
Is there some way these narrative text linking id's could be a special type of identifier rather than an actual Resource id?
oh. it is. It refers to Bundle.entry.id, which is whatever you want it to be. I just reused the id of the resource because I'm lazy; it totally can be any valid id you want
Perfect! Thank you @Grahame Grieve .
@Grahame Grieve , I've been thinking deeply about the question of contained resources for representing a document. Do you have any advice on how to make that decision? When would it be right to make the entries contained resources rather than free floating entries in the document Bundle. I sort liked the document Bundle with referenced Resources because it gives the flexibility to handle the resources independently, but you don't force a recipient system to have to instantiate them because they can just let them sit there in the confines of their Bundle. Do you see any reason I should be considering to make them fully contained within the Composition, or is containing them withing the Bundle sufficient "containment" of sorts?
DomainResource.contained is only intended for use when the resource doesn't have an independent existence or identity from its parent. i.e. in the source system, the resource isn't referenced by (and can't be referenced by) anything other than the parent. As an example, you might have a system that captures the details of a compounded medication as part of the prescription rather than as a shared structure. It might do the same with the name and phone number of the prescriber. In that case, the MedicationRequest would reasonably have Medication and Practitioner as 'contained' resources. On the other hand, if the system allows for multiple prescriptions to point to the same drug 'recipe' and prescribers are always pointers to an internal registry of possible clinicians, then it would not be appropriate to 'contain' those resources - they have independent identity.
We don't use 'contained' as a handy packaging mechanism to avoid needing to transmit separate resource instances.
@Lloyd McKenzie Thanks for that clarification. I'd like to extrapolate from the example you provided to my specific situation. You explained, "As an example, you might have a system that captures the details of a compounded medication as part of the prescription rather than as a shared structure. It might do the same with the name and phone number of the prescriber. In that case, the MedicationRequest would reasonably have Medication and Practitioner as 'contained' resources." In my case, I have a portable medical order which may have been authored by a doctor who is not in any way involved with he healthcare provider/system where that advance healthcare directive is being shared. That organization doesn't want to create PractitionerRole, Organization, or Practitioner resources on their recipient system. I was thinking this might be a good example of when to include this information about the PMO authoring physician's information as contained resources?
What the receiving system wants to do (or doesn't want to do) isn't the sender's problem. If the sender says "these things have independent identity", then they should be transmitted that way. What the receiver chooses to do is up to them. We don't want the sender to adjust how they send data based on how a particular receiver might want to store the data. The sender can't reasonably split data into separate identified resources if it has no clue whether "Dr. Bob" on prescription 1 is the same "Dr. Bob" as is on prescription 2. But if it does know that, it should be reflected in the data being shared. If the receiver wants to collapse the data together, it can (though obviously there's information loss when it does so).
We're considering a different use case. We want to share the date a Condition was last updated by a clinician. Our EHR vendors can provide that since it's in their db structure, say: SELECT date_updated FROM Problem WHERE Problem.id = 123, which can be wrapped in Provenance. Of course, date_updated has no independent existence: once Problem 123 is deleted, it is gone too, but it could be independently identified since this is a 1:1 relationship (say Provenance/problem123dateupdated would be a unique id). We haven't decided how to implement this yet, but can the general rule be reversed: if there is no independent existence, it is better to use a contained resource? @Lloyd McKenzie
If there is no independent existence and no independent identity, then from a RESTful perspective, you pretty much have to use contained. The way you expose data in a document should be consistent with how you'd expose it restfully if you had a restful interface.
@Marc de Graauw Since Provenance.target points to this Condition resource instead of the other way around: are you able to use Condition.contained at all? Do you add an additional extension on Condition that points to Provenance to satisfy that the parent shall point to the contained resource? (circular reference)
So long as there’s a connection one way or the other, containment is still possible
If Condition is resolvable, you could put an absolute uri in .target. Alternatively, use an identifier. Seems indeed one can point to a contained resource using a relative uri (#) but cannot point to the containing resource in a similar way (i.e. use '..' or something)
Note on invariant dom-3:
STU3:
If the resource is contained in another resource, it SHALL be referred to from elsewhere in the resource
R4 and later:
If the resource is contained in another resource, it SHALL be referred to from elsewhere in the resource or SHALL refer to the containing resource
For IPS you are good. For our Dutch BgZ which is STU3 you would technically run into the issue that Condition has no native way to point to Provenance.
but I do not enforce that in STU3
If we would use Provenance contained in Condition in STU3 then that probably deserves a solid note in the IG
yes, please do. The R4 dom-3 rule was the intention all along.
It is my understanding that contained resources do not nest i.e. all relevant such resources form a flat list within (the outermost) containing resource, correct ?
Does the dom-3 rule prohibit transitive references from "tangling resources" ? So I'm searching for clearly worded, authoritative guidance for contained resources that a) do not reference the containing resource directly and b) instead reference some other contained resource that (in turn) satisfy dom-3 (or not) ? And to me the main unclear issue is that b) should actually cover reference chains leading to contained resource that can be tested to fulfill dom-3.
And yes, I'm aware that this kind of "closure" validation for contained resources is computationally rather heavy and there's probably no practical way to actually enforce it.
the validator checks it
and it is rather a challenge in big bundles
but yes: flat, and contained resources can reference other contained resourcdes
Thank you for confirmation, so transitive reference chains in contained resources do satisfy dom-4.
Some background for the curious: For cross-border use of medication information it is necessary to describe the medical product explicitly by its attributes (since there's no global identification schema, nor product characteristics database, etc. currently in use). Hence, one (and by no means the only one) way to achieve this is to use a (very) limited subset of the FHIR definitional resources for medications (especially for R5 and above). Which do natively tend to have their reference links "backwards" from the point of view using them as contained resources. And they can form multi-step chains if the definitional resources for substances/ingredients, "abstract medical products" etc. are fully taken into account. This is also a use case where it kind-of makes sense to use contained resources, just maybe.
Interesting example
I have recently come across two version sorting challenges that the artifact-versionAlgorithm extension provides no help with (leading me to think it adds almost no value except as documentation).
The first is a CodeSystem that has changed strategies from semver to datestamp; how can I sort these without special-case knowledge. The extension doesn't help with this - what do I do with two CodeSystem instances with the same URI but each declaring their version conforms to a different format?
The second is RxNorm using MMDDYYYY format ! (https://terminology.hl7.org/RxNorm.html). Firstly, this is not easily sortable without explicit parsing, but then I need to know the format, and none of the format types for the extension include this one. In fact the closest "ISO Date", (I assume meaning ISO 8601), but that is strictly "descending notation".
I am left wondering if we would have been better off (for sorting purposes) with an order-like extension.
leading me to think it adds almost no value except as documentation
I'e always thought that
Isn't there a fhirpath option for the sorting?
So you should be able to use that to do the comparison.
https://hl7.org/fhir/structuredefinition-definitions.html#StructureDefinition.versionAlgorithm_x_
However I do agree that you'd need to update the old version instance with the change to make them consistent for things to really work.
My facade project does the resolution like this, and has error when inconsistent
https://github.com/brianpos/fhir-net-web-api/blob/51a514e5d15b90d9e314da5a6823a179a67dad31/src/Hl7.Fhir.DemoFileSystemServer/CanonicalResourceService.cs#L75
So you should be able to use that to do the comparison.
https://hl7.org/fhir/structuredefinition-definitions.html#StructureDefinition.versionAlgorithm_x_
That still doesn't help - different resources are disagreeing about the algorithm. You can't resolve that in the resources themselves - it's a system property
Yup, that's why my code complains and reports an error if the algorithm is different between the instances being considered.
And you'd need to fix the data to perform it in the service.
(manually tell the system which should be used by updating all with the canonical to be consistent)
image.png
Can someone clarify the difference between these two library IGs?
Julia Skapik said:
image.png
Can someone clarify the difference between these two library IGs?
There’s actually a third one though at least it’s obviously an older version (0.0.1 instead of 1.0.0). US-PHPL https://build.fhir.org/ig/HL7/fhir-us-phpl/
Yup, that's why my code complains and reports an error if the algorithm is different between the instances being considered.
Interesting. Although it's not necessarily the case that different algorithms are incompatible. integer, alpha, date, and natural should all give the same order for datestamps in "descending notation" with consistent syntax (eg all YYYYMMDD or all YYYY-MM-DD).
Ontoserver's approach is to break the version strings into a sequence of tokens whenever there's a switch from digit to non-digit. Then tokens that are all-digits are sorted as numbers, and other tokens are alpha sorted. The token sequences are compared pair-wise left to right so that 2.3.4 and 2.3 can be compared.
@Anil Patel Yes, but version is a string, so there's no type checking for valid semantic versioning or a particular date/time format. usually people will use either semVer or a YYYYMMDD/YYYY-MM-DD, but that's not guaranteed to be the case.
And sometimes with random suffixes (-RC1, final, alpha, mjl-mod-1, etc), and sometimes prefixed with v, V, ver, etc or even 1st Ed, 2nd Ed, ...
And, even in FHIR / THO code systems, switching from one scheme to another.
we did that? where?
Not the example I'm thinking of (semver -> datestamp) - I'm still trying to git it up, but the stub CodeSystem for LOINC has version 3.1.0, but it should follow the LOINC naming convention - e.g., 2.78 (which is smaller/older in semver terms!) - see https://jira.hl7.org/browse/UP-591
Including FHIR Identifier.system URL's in CDA II.root can be hard. If the system uri is urn:oid: or urn:uuid:, it's easy. If it's an http(s) URL one could try to look it up in one of the registries which map URLs to OIDs, but if this does not work you're out of luck. We still need FHIR<->CDA conversion for some time don't want to loose identifiers.
In the Netherlands we're considering an algorithmic solution: urlencode the URL, get the ascii value for each character, append after '2.16.840.1.113883.2.4.3.46.30.' (or some other agreed upon OID) and use that. So 'http://example.org' would become '2.16.840.1.113883.2.4.3.46.30.104.116.116.112.58.47.47.101.120.97.109.112.108.101.46.111.114.103' etc. and store that in II.root. A drawback is OIDs can get long (some jurisdictions have length restrictions for II.root) but it's a generic round-trippable solution. Same of course could be used for CD.codeSystem etc. (Although those would sooner be expected to be expected to be in some registry, and that OID should take precedence.)
Any problems or comments? @Tom de Jong @Alexander Henket ⚒️
What about (unless you are required to use @root):
Fhir .system is oid, uuid, ruid -> CDA @root
Fhir. system is url with no known oid conversion -> CDA @assigningAuthorityName
Fhir .system is a url with a known oid -> CDA @assigningAuthorityName, @root (known oid).
CDA back to FHIR, prefer @assigningAuthorityName over @root.
That's an alternative. It tweaks the definition of assigningAuthorityName
This name may be provided solely for the convenience of unaided humans interpreting an II value and can have no computational meaning.
Which may or may not be a problem. If it's only FHIR to CDA and back it's no problem but in a mixed environment parties may not expect this.
CD does not have an attribute like II.assigningAuthorityName.
But even if it did: what do you put in @root or @codeSystem? There is no system in use today in our realm that would understand an @extension or @code without a @root or @codeSystem.
Note that contrary to string-to-codepoints()
and codepoints-to-string()
we currently forbid systems in NL to send urls of their own making and use oids instead. This is the only way we know how to have a working hybrid ecosystem.
Obviously: where applicable we define system urls for known code systems and identifier systems so there is a workable 1-to-1 mapping in those cases
Alternative #2:
Instead of url encoding the url and getting the ascii value to create oid with 100's of segments. Just create a lookup table for all new .system values you come across.
2.16.840.1.113883.2.4.3.46.30.1 = https://first.com
2.16.840.1.113883.2.4.3.46.30.2 = http://somebodyunknown.org
2.16.840.1.113883.2.4.3.46.30.3 = http://someotherplace.edu
...
solves the length problem and is reversible.
That doesn't quite work in production.
It's no different than making up a new oid based on the ascii values of the .system value.
Yes it is ... the result of string-to-codepoints()
, a well known function, is the same regardless of the hospital you apply it in.
They don't know the .system value now, can't know because they can't do fhir. Why would they want to undo the oid into the .system value that they have no use for?
They do know the @root and @codeSystem today because in NL:
Hence: today we always can populate @root and @codeSystem with the appropriate oid
But ... we sometimes get pushback from FHIR native systems because they like creating their own urls and to be fair: FHIR does nudge you in that direction.
We would not be pushing back on urls if V3 compatibility wasn't a requirement. So ... how do other countries handle this? There must be more places where CDA meets FHIR for example
Undoing the OID may be useful when you receive FHIR, convert to v3, then send some v3 to some other party who does understand FHIR system URL and wants to reconstitute the original .system URL.
In the Netherlands we require urn:oid as in @Alexander Henket ⚒️ bullet 3, but that is a national, not an international solution, which is less desirable
The lookup table is required anyway ... there is no V3 system in the world that would handle:
<code code="327671006" codeSystem="104.116.116.112.58.47.47.115.110.111.109.101.100.46.105.110.102.111.47.115.99.116"/>
the only useful way would be:
<code code="327671006" codeSystem="2.16.840.1.113883.6.96"/>
That long thing in the first <code/> is string-join(string-to-codepoints('http://snomed.info/sct'), '.')
But ... if we hadn't had length restrictions in our realm ... the string-to-codepoints() solution would certainly be a valid solution for urls without a 1-to-1 mapping to an oid. Hope to learn how other realms approached this.
Hello - when is it appropriate to use contained resources vs. creating a full resource? Is there any guidance on when to use contained resources. I see this in the description comments for the 'contained' data element on each resource: "This should never be done when the content can be identified properly, as once identification is lost, it is extremely difficult (and context dependent) to restore it again"
Can anyone share example scenarios of when they used contained resources vs. creating a full resource?
Thanks!
a typical scenario for using a contained resource is when converting from v2 or CDA to FHIR, and the only information you have for the Practitioner details is 'Mr John Smith' - you don't know which john smith. This is unidentified, and therefore you have to use contained resources
iif you don't have to, you shouldn't
when you don't have sufficient detail to fill out that resource usefully or causing noise. In my case I am decomposing a lab result, I have the various lab measurement types and values; but I don't have any business identifier to keep me from generating alot of duplicate Observations data. Thus it is saved as a contained Observation within the DiagnosticReport, as I do have a business identifier of the lab report.
I don't wish to confuse things, but if all you know is the single data point "Mr John Smith" (as a string) isn't that suitable for putting in reference.display, and not need a contained? I think that is a legitimate use. If you know another data point (e.g. phone), then that would require contained.
I always use the maxim of "does the resource have a lifecycle of its own? then don't put it as a contained resource."
Many implementers and IG authors use contained as a way to get around the FHIR reference mechanism. If you manage a resource's state and have an id for it, it should not be contained.
One thing I've heard on here is, using a contained questionnaire on a questionnaireresponse resource to indicate the questions as they were when answered.
The QuestionnaireResponse.item.text already does that. The only use case I’m aware of for contained Questionnaires is for adaptive forms where the Questionnaire is built on the fly for that specific response
There are some resources - like Location, that require only 'name', which could be anything. Seems like this would definitely be a candidate for a contained resource. I have not seen these in the wild yet, so not sure what will be populated in them. But I question how useful they are as stand alone resources.
Similar discussion with some other use cases here: #IPS > Contained vs Referenced Resources in a document Bundle
@David Hay and I have been playing with the definition based extraction functionality and creating samples and a test environment and have come across one limitation and a possible way to work around it.
How can we set a value in the output resource without needing a specific profile to set the value, or have a pointless hidden field in the questionnaire that serves no purpose except for the extraction.
What we came up with is the following:
"extension": [
{
"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemExtractionValue",
"extension": [
{
"url": "definition",
"valueCanonical": "http://hl7.org/fhir/StructureDefinition/Patient#Patient.extension.url"
},
{
"url": "fixed-value",
"valueString": "http://example.org/Str ..."
}
]
}
],
This extension will be able to go on any item (or root) in the questionnaire and if that item is answered, then the values in the extension will also be set into the output resource.
A second variation of this would be instead of the fixed-value
would have an expression-value
that has for it's value an Expression type that would be evaluated at that point and if there are any results - those would be set into the identified definition property in the output resource.
These expressions would have a limitted number of variables available, and most significantly would NOT have access to the launch context variables, as they are unlikely to be available in many places this would be evaluated.
However it does have access to the QR.subject/QR.author which is usually what comes from the launch context anyway.
Thoughts?
To provide another example, here would be how we could populate the obseravation's patient reference from the QR:
"extension": [
{
"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemExtractionValue",
"extension": [
{
"url": "definition",
"valueCanonical": "http://hl7.org/fhir/StructureDefinition/Observation#Observation.patient"
},
{
"url": "dynamic-value",
"valueExpression": {
"language": "text/fhirpath",
"expression": "%resource.subject"
}
}
]
}
],
Putting it in simplest terms this extension is for:
I've implemented the fixed-value portion of this in my demo server (will get a live example posted during the week - unless David beats me to it)
I've also noted that we've documented that the output of the operation is a transaction bundle, however we've not defined how to populate the fullUrl field, or request fields to drive method=PUT/POST or ifnone match etc.
Is that something I've just missed, or shall I log this?
(also applies to observation based)
Would be good to support conditional create / update...
I am just wondering why people are still exploring poor ways of doing extraction such as definition and observation based while a real good way of doing it doesn't move forward https://jira.hl7.org/browse/FHIR-39498 ?
That's on my list for the week after next.
Here's a new sample covering the proposed new fixed-value
extension.
https://dev.fhirpath-lab.com/Questionnaire/tester?tab=csiro%20renderer&id=https%3A%2F%2Ffhir.forms-lab.com%2FQuestionnaire%2Fcanshare-myPatientNoProfile
It shows the new issue we found trying it out - which I added to the tracker item.
Brian Postlethwaite said:
Putting it in simplest terms this extension is for:
- Any content in an extracted resource that is not directly set by a value that the user entered into an answer in the QR - and doesn't come from a fancy profile
Looks like calculatedExpression
extension fits this case? We use it to set subject when extracting Conditon or MedicationStatement
Which would then replicate the subject into another field in the response.
Which is what this approach is seeking to avoid.
Brian Postlethwaite said:
That's on my list for the week after next.
I am happy to collaborate and build a reference implementation with python.
When I get back home I'll reach out and we can iterate together.
If y'all haven't seen notebooklm.google.com it's pretty fun. It can take zulip threads like #terminology > Overuse of the Experimental flag and turn them into, um... podcasts ;-)
Example Output: vocab2.mp3
That’s fascinating. It’s interesting how it’s pulling in all kinds of info not actually present in the conversation.
Yeah, intrigued as to how much additional context you added in
What I did was to curl the zulip message history of this stream, using the zulip json format, and I literally pasted that json into notebook LM as a source document. And then I clicked the button.
Note that the json stream does have details on names, timestamps, etc. but for sure when it calls Grahame "Grieves" the "grandfather of FHIR," that did not appear anywhere in the json.
It is a weird but prescient little experimental tool. It Is mostly about asking questions of your source documents, but the source documents selection page exposes a little "generate audio" button with zero configuration or prompt control.
Grahame "Grieves"
thereby demonstrating a very human like mode of thought
"what could be more exciting that developers arguing about standards". Awesome
it is a weird piece of performance art, I have to say. And us humans are doomed.
Grahame Grieve said:
"what could be more exciting that developers arguing about standards". Awesome
When I heard that my first thought was, "did I just get dissed by an AI?"
Josh Mandel said:
Note that the json stream does have details on names, timestamps, etc. but for sure when it calls Grahame "Grieves" the "grandfather of FHIR," that did not appear anywhere in the json.
Which makes me wonder who is the father, or certainly the mother :smiley:
Hey,
We are currently building our medication data in our FHIR server (Azure Health Data Services) (R4). I am having a hard time understanding the relation between Medication and MedicationKnowledge. It seems like the 2 entities have a clear parent-child relationship however I find it hard to search with the available search parameters.
Example: I expected to be able to search the list of medications and then _include the MedicationKnowledge:associatedMedication however it is not in the search parameters. The only way I can find to do this is possibly with the code? I assume we always expect the code to be the same between the medication and medication knowledge?
To note: We are a canadian company and are loosely following us core & canada profiles but not enforced them since this integration is not meant to be used with external clients.
It seems a lot of info are duplicated between medication and medication knowledge and medication is kind of an empty shell and we should just use medication knowledge. Can we use medication knowledge without medication object? Does it make sense? Thanks
If you are searching Medications. Then MedicationKnowledge:associatedMedication is a _revInclude.
Medication describes a bottle of pills, for example.
And of course, the MedicationKnowledge does have to have populated references to Medication instances.
When I do this I have the following error:
The search parameter 'associatedMedication' is not supported for resource type 'MedicationKnowledge'.
Here is the search query I am using (note I am using the firely dotnet sdk):
var searchParams = new SearchParams();
searchParams.Add("_id", medicationId);
searchParams.Add("_revinclude", "MedicationKnowledge:associatedMedication");
var bundle = await client.SearchAsync<Medication>(searchParams);
You are correct, there is no "associatedMedication" search param on MedicationKnowledge. Submit a jira ticket that says, it'll be very useful to have such. Then if/when such a search parameter is defined, you'll be able to do your include functionality (assuming your server has implemented it).
Until then you'll need a solution that doesn't require the server to implement the join for you.
Could I manually add a search parameter that does that in the meantime? I have added a couple search params on custom extensions i'm assuming I could do the same here?
Or i'm thinking perhaps the link between the 2 is expected to be the code (SNOMED Code?) I assume this would be unique per medication?
If the server you are talking to allows you to add a reference type search param and it propagates into the include dictionary, go ahead. I can't tell you the capabilities of the FHIR server you are using.
Re using MedicationKnowledge without Medication (and their logical relation)
Quite possible (see Scope and Usage chapter for MedicationKnowledge) but the answer remains "it depends". As other relevant resources in FHIR are mostly using references to Med (not to MedKnow), so not having them might quickly become a problem.
To further complicate matters, if the intent is to build a full, stand-alone medicinal product database a) there's a Medication Definition module in FHIR and b) R4 might not be the absolutely best choice to do that. For going deeper down that rabbit hole, Zulip has a dedicated Medication stream and ISO IDMP data model (and definitional module in R5) might be useful to be slightly familiar with.
In a way, one could think MedicationKnowledge as clinical workflow oriented, drastically simplified "version" or "summary-of-sorts" of the much bigger, very detailed, regulatory medicinal product data model.
@Kari Heinonen could you share links for the zulip medication stream you are talking about? This is all brand now to me thanks!
R5 for now is not really an option for us due to the server we are using doesn't support it
Here you go #Medication
Thanks will ask there :)
Yes, I did assume that R5 would not be an option. IMHO it might be still useful to take a peek at R5 and IDMP stuff anyway to "see where the river is taking us". And the R4 definitional resources I mentioned are listed as the very last group, bottom of page on
https://hl7.org/fhir/R4/resourcelist.html
And as it happens Medication data modelling related issues are quite relevant for EU currently (and me personally, hailing from Finland). I think I can answer (albeit always associated with big disclaimer :smile:) some more specific questions if you have any.
it's a little while since I worked with javascript, and I'm bamboozled by something
I execute this javascript:
function go(id, ver) {
var div = document.getElementById('target');
if (div != null) {
var json = getJson();
div.innerHTML = '<p>'+json+'</p>';
}
}
async function getJson() {
const url = "some-document.json";
try {
const response = await fetch(url);
if (response.ok) {
return await response.json();
} else {
return null;
}
} catch (error) {
return null;
}
}
that seems straight forward to me from the documentation, but when I run this, I get [object Promise]
as the output, not the actual json. What am I doing wrong?
I'm not being snarky, language models are just better than I am an answering these questions.
The issue you're experiencing is a common confusion when dealing with asynchronous JavaScript. Let's break down what's happening and how to fix it:
In your original code:
function go(id, ver) {
var div = document.getElementById('target');
if (div != null) {
var json = getJson();
div.innerHTML = '<p>'+json+'</p>';
}
}
async function getJson() {
const url = "some-document.json";
try {
const response = await fetch(url);
if (response.ok) {
return await response.json();
} else {
return null;
}
} catch (error) {
return null;
}
}
getJson()
is an asynchronous function, but you're calling it synchronously in the go()
function. When you do this, JavaScript returns a Promise object instead of the actual JSON data, which is why you're seeing [object Promise]
.
To fix this, you need to make the go()
function asynchronous as well and use await
when calling getJson()
. Here's how to modify the go()
function:
async
keyword to the go()
function declaration.await
when calling getJson()
.JSON.stringify()
to convert the JSON object to a string for display.Here's the corrected go()
function:
async function go(id, ver) {
var div = document.getElementById('target');
if (div != null) {
var json = await getJson();
div.innerHTML = '<p>' + JSON.stringify(json) + '</p>';
}
}
This change allows the function to properly wait for the JSON data to be fetched before trying to display it.
When you call go()
from elsewhere in your code, you'll need to handle the fact that it's now an asynchronous function. For example:
go().catch(error => console.error('Error in go():', error));
Or if you're calling it from another async function:
await go();
In asynchronous JavaScript, functions that perform operations that might take some time (like fetching data from a server) return a Promise. A Promise is an object representing the eventual completion or failure of an asynchronous operation.
When you use the await
keyword, you're telling JavaScript to pause the execution of the function until the Promise is resolved (or rejected). This allows you to write asynchronous code that looks and behaves more like synchronous code, making it easier to understand and manage.
By making these changes, you ensure that your code waits for the JSON data to be fetched before trying to display it, resolving the issue of seeing [object Promise]
instead of the actual JSON data.
thanks.
the alternative is to use then(.....)
rather than propogating the async up the call graph.
Which usually stops at the event handler.
I just wanna give a big-axx salute to the synthea team for making an awesome tool for generating synthetic data that is easily extendable and without a sxxt-load of magic. You guys nailed it!
Thanks @Jens Villadsen , we appreciate the praise, and we're glad you find it useful.
Especially the flexporter feature is a nice addon
@Jason Walonoski - btw - one of my colleagues asked if adding/loading js libs could be an option so that one could use js util functions for different cases upon generation in the flexporter
@Jens Villadsen thanks for the kind words!
Re: flexporter support for loading JS libraries, this is something we've explored a little but it wasn't super user friendly and I wasn't sure how far down the rabbit hole to go at that point. Limited support does exist if things are in the right place but it's not currently exposed via the mapping file. https://github.com/synthetichealth/synthea/blob/master/src/main/java/org/mitre/synthea/export/flexporter/FlexporterJavascriptContext.java#L21
I just opened https://github.com/synthetichealth/synthea/issues/1505 for this feature request, please chime in with any thoughts or specifics you might want to see
Thats good enough for us to play around with. Perfect!
(deleted)
Hi! In the FamilyMemberHistory resource the .condition.onset
element has possible data types Age, Range, Period and string. Why hasn't the option dateTime been added here as well? Especially, since .procedure.performed
includes dateTime as one of its allowed data types, and the familymemberhistory-abatement extension includes the date data type for its value
, and I'd expect similar data types to be present for these three elements.
Background of the question: in the logical model that I need to map to FHIR, the condition of the family member has a start and end date (the onset and abatement date, respectively). In order to map the start date properly to FHIR, it is currently necessary to use the Period data type, and then add guidance on how to fill the .onsetPeriod.end
element (as leaving it empty implies an ongoing onset period, which is not (necessarily) true).
@Michelle (Moseman) Miller
Patient Care briefly discussed this today and would welcome a change request (JIRA) be logged with example use cases that would warrant onset precision of date or dateTime.
Thanks @Michelle (Moseman) Miller! I have asked the team that is responsible for the logical model to supply some use cases. Afterwards I'll create a change request accordingly.
Luud Slagter said:
Thanks Michelle (Moseman) Miller! I have asked the team that is responsible for the logical model to supply some use cases. Afterwards I'll create a change request accordingly.
Hi!
What's the status of this? Im facing the same problem with trying to store onsetAge.value: 0
and I think that the possibility of storing date can solve this.
Hi @Oren Banda! Unfortunately I've not yet received any example use cases from the logical model team, hence I haven't created a change request yet.