Stream: implementers
Topic: Supported Vs 1..1 Cardinality
Joel Francis (Jan 15 2019 at 16:53):
Having a chat with one of the attendees at the Conformance WGM, requires me to get some clarification on supported vs 1..1 cardinality
A element with a cardinality of 1 "may not" be supported by the receiving system but a supported element may be empty. Does it mean that all supported elements have to have a cardinality 1..1?
Any help is appreciated. Thanks
@Heather Patrick
Patrick Werner (Jan 15 2019 at 17:08):
no they don't. You can have must-support elements with a 0..[something] cardinality.
Patrick Werner (Jan 15 2019 at 17:09):
from: https://www.hl7.org/fhir/elementdefinition-definitions.html#ElementDefinition.mustSupport
Patrick Werner (Jan 15 2019 at 17:09):
If true, implementations that produce or consume resources SHALL provide "support" for the element in some meaningful way. If false, the element may be ignored and not supported. If false, whether to populate or use the data element in any way is at the discretion of the implementation.
Joel Francis (Jan 15 2019 at 17:11):
no they don't. You can have must-support elements with a 0..[something] cardinality.
@Patrick Werner thanks. So a missing element with a cardinality of 1..1 is non-conformant with a profile that deems it 1..1 where as a must supported is allowed to be empty or have the element missing completely?
Simone Heckmann (Jan 15 2019 at 17:15):
The latter. Empty Elements are not allowed.
Joel Francis (Jan 15 2019 at 17:17):
The latter. Empty Elements are not allowed.
Thanks @Simone Heckmann
Patrick Werner (Jan 15 2019 at 17:36):
Cardinality is validation focused, where must-support is implementation focused. 1..1 with must-support=false doesn't make logical sense, but is technically allowed. ( At least i haven't found something forbidding it)
Simone Heckmann (Jan 15 2019 at 18:06):
I think I remeber someone mentioning once that implementations could theoretically comply with 1..1 requirements without actually supporting the element in any meaningful way by e.g. populating the element with hardcoded values...
Grahame Grieve (Jan 15 2019 at 18:14):
that is very much the case
Heather Patrick (Jan 15 2019 at 18:38):
I'm still not getting how conceptually data is required to be present, but it's okay for the receiving system not to support it.
Joel Francis (Jan 15 2019 at 18:54):
I'm still not getting how conceptually data is required to be present, but it's okay for the receiving system not to support it.
I think as @Patrick Werner describes it, it may be required that the information be present but a particular receiving system with not-supported = false will not be required to process that element and may even choose to ignore it.
Michael Donnelly (Jan 15 2019 at 19:13):
If I'm reading it right: 1..1 means that the element has to be present for the resource to be valid. So if mustSupport is false, that means that the profile doesn't particularly care about that element, though they still aren't allowed to drop the element entirely. So a producer could populate it with a hard coded value, and a consumer could ignore it, and both would be compliant with the profile. If the producer didn't include the element or the consumer threw an error when the element is populated, they would be in violation of the base spec.
Eric Haas (Jan 15 2019 at 20:53):
Must Support is defined for each implementation and describes the expected behavior of both parties and the server requirement may indeed be different from the client. i.e. the server must represent the data in the must support element and the client must not raise an error if it is supplied. - here there is very little expectation on the client.
Lloyd McKenzie (Jan 15 2019 at 21:28):
A good example is Patient.deceased[x]. You certainly wouldn't ever make it mandatory (unless you're a death reporting application), but you might make it mustSupport (system must be capable of sending if it applies, receiver must be capable of receiving and doing something useful with it.)
Richard Townley-O'Neill (Jan 16 2019 at 00:11):
We have a use case for List where the only value for mode is "snapshot". In the resource mode is 1..1. In our profile mode is fixed to "snapshot" but is not "must support". The writer has to populate it with "snapshot", and the reader can ignore it.
John Silva (Jan 16 2019 at 13:37):
Wow, this sounds suspiciously like the "RE" in V2 conformance? The notion was that if the sender has the data they are Required to send it but if they don't then the value can be Empty. (I don't remember the receiver requirements.) Is this FHIR notion a similar conformance construct?
Grahame Grieve (Jan 16 2019 at 13:52):
it's similar, yes
Eric Haas (Jan 16 2019 at 14:04):
The fact that the authors of implementation guides define the behavior of Must Support means it can be exactly like RE or can be subtly or markedly different.
Lloyd McKenzie (Jan 16 2019 at 14:04):
The specific meaning of "must support" is actually IG/profile-specific. The profile or IG is required to define the meaning in the context of that IG. Possibilities include: must expose on a screen, must store, must consider in processing logic, etc.
Ken Sinn (Feb 12 2019 at 20:40):
Last week, we had the opportunity to discuss our implementation profiles with Lloyd M. and Iryna R., and one of the key pieces of feedback was to avoid profiling with 0..0, even with out strictly outbound/egress resources, and to use the MustSupport flag to indicate to implementers that data will be sent in the elements flagged as "MustSupport", if available (whether the field is 0..1, 0.., 1..1, 1.., etc).
One of the key reasons cited for leaving the unused elements unchanged was to maintain flexibility, in the event that those elements were introduced in a later update to our implementation.
Is this the approach that most implementers/profiles are taking? I've seen that the Argonaut project has adopted the MustSupport approach, while Nictiz in the Netherlands is not using MustSupport but also not using 0..0 for unused fields (https://simplifier.net/nictizstu3-zib2017/nl-core-patient). Meanwhile, Finland is not using MustSupport, and is using the 0..0 to indicate unused fields (e.g. https://simplifier.net/finnishphr/fiphr-patient-stu3).
Just wanted to get an assessment of how widespread this approach is, e.g. using MustSupport to indicate that a field is sent, and lack of MustSupport to indicate otherwise.
(I did look at https://chat.fhir.org/#narrow/stream/179177-conformance/topic/.22Mute.22.20button.20for.20StructureDefinition.20elements, plus many other threads, for the current discussions/thoughts on the topic)
A second question, how are people handling situations where the base resource definition allows 0.., but your system only supplies 0..1 (egress) or allows/consumes for 0..1 (ingress)? For example, patient.name is 0.., but we only ever send back one patient.name from our repository. Are implementers/profilers profiling this as 0..1, or are they leaving it as 0.., and defining a 0..1 slice w/ MustSupport? How do you codify the discriminant of a single instance that may not have any distinguishing values, aside from forcibly applying one, e.g. forcing the instance to have patient.name.use=official? Or in the case of something less distinguishable, patient.address.line being 0..2 instead of 0.. -- is there a way to have a blank discriminant, for all the elements where we constrain from 0..* to 0..1? That's a lot of extra noise for an implementer to parse in a profile, instead of a strict contraint from 0..* down to 0..1.
Ken Sinn (Feb 12 2019 at 20:45):
Incidentally, I was looking at the Argonaut profile for patient, and noticed that patient.name.family is 1..* -- doesn't that result in non-conformance against the FHIR standard, where patient.name.family is 0..1?
Lloyd McKenzie (Feb 12 2019 at 20:50):
Argonaut is based on STU2, where family was also 0..*
Lloyd McKenzie (Feb 12 2019 at 20:56):
Profiling the "emitting" side is sort of a question of cost now vs. cost later. If you only emit one now and are confident that there's zero chance in the next 30 years that you'll ever emit more than one, then defining slices that distinguish your current "1" from amongst a possible selection of others is unnecessary. However, if you define 0..1 now and then in two years start emitting 2 or 3, you can't do that without forcing clients who built to the original interface to update their interfaces. Even if they continue to only display 1, they'd have no way of knowing which one to display. However, if you take the slicing approach, then an implementer who rolls out the original interface will happily tolerate the presence of additional repetitions, even though they're only exposing one - because the slicing rules told them which one to grab.
So - more effort to define (and understand) the profiles, but simpler and lower-cost upgrade path because there's not a need to coordinate and do a big-bang update.
Lloyd McKenzie (Feb 12 2019 at 21:02):
Profiling the consuming side has the same sort of thing. If you expect systems to only supply 1, but in the future might allow multiple, then you might want to require the inclusion of metadata now that will distinguish what "kind" of repetition is being sent when there might be more than one kind in the future. (E.g. use="official"). However, the consuming side adds on the question of whether you expect clients to talk only to your system or whether they'll be talking to others as well. If clients will be talking to multiple systems and you impose constraints prohibiting data you could ignore, then that means the client is forced to create (and maintain) a custom interface to talk to your server. That will drive two things - increased costs for clients, and/or decreased number of clients that can talk to your server. It will also increase migration costs because if you add support for things you used to prohibit, you'll either need to force everyone to migrate simultaneously or you'll have to maintain and manage multiple interfaces on the server side (and handle conversion) as you share data between systems that are providing a new element and systems that are told to prohibit it.
Ken Sinn (Feb 12 2019 at 21:07):
So for both exposing and consuming profiles, whenever there's a constrain down from 0..* to 0..1, all such elements need to be sliced for must-support, if we were to adopt these best practices? Should these best practices be documented somewhere, other than here in the chats, as an official FHIR recommended approach?
As demonstrated by our own profiles, and those of finland and netherlands, this approach is un-intuitive (maybe just for lack explicit documentation) -- it's very different from the v2 and v3 approaches, and is worth fully expanding upon, if this is FHIR's position. Otherwise, leaving "Must-Support" to be defined by implementers leaves signifant gaps, and goes no further in supporting interoperability if not everyone is adopting the same approach.
Lloyd McKenzie (Feb 12 2019 at 21:10):
If you're consuming and want to allow for receiving more than one in the future, then yes slicing would be best practice. We've committed to writing some profiling best practices, but other things have gotten in the way of that.
I strongly agree that slicing isn't terribly intuitive to define or to read when looking at profiles. The intuitive reaction of most first time profilers is indeed to just constrain cardinality - even though that might not be the most desirable thing from a long-term cost perspective.
Grahame Grieve (Feb 13 2019 at 11:12):
I would not like to slice just for must-support on the first slice. And given the information gap implicit in must-support (see my blog here http://www.healthintersections.com.au/?p=2908, and read the comments), it seems unnecssary to slice - just mark it must support and explain what you mean
Lloyd McKenzie (Feb 13 2019 at 16:12):
The reason for slicing is to distinguish which "1" of the potential many you expect systems to deal with. Not slicing means the implementer doesn't have the information on how to extract from a potential future collection - which means that changing to a collection in the future becomes much more difficult
Ken Sinn (Mar 06 2019 at 14:36):
@Lloyd McKenzie on a similar related topic, is there any profiling guidance/best-practice around constraining of bindings? For example, consider an outbound/egress profile. There is an element with extensible binding strength, from ValueSet {A,B,C,D,E}, and our interface uses ValueSet {A,B,C,P,Q}. Is the best practice to:
A) bind to ValueSet {A,B,C,P,Q} and keep the binding as extensible or
B) bind to ValueSet {A,B,C,P,Q} and keep the binding as required?
A subsequent/future inbound/ingress profile would produce errors, if values D or E are sent, as they are not accepted.
Lloyd McKenzie (Mar 06 2019 at 16:08):
The general recommendation is to follow Postel's law: be tolerant when receiving and strict when sending. Extensible also raises some questions as it matters whether P or Q are sub-concepts of A, B, C, D or E. If the answer is "yes" then the expectation is that if you're going to support P or Q, you must accept the corresponding broader concept too.
In the end, the profile that corresponds to your interface should reflect what you'll accept and what you'll do something useful with. The binding for an element defines the 'max' value set - the set of codes that won't result in an error if they're met. The 'min' value set - the set of codes that must actually be supported can be conveyed by an extension. If you're going to raise an error if a given code is the only one that's present, then it shouldn't be in the max value set and the binding shouldn't be extensible. (Whether the profile for your implementation is conformant with the base spec is a different question :))
Shamhad Abdi (Apr 08 2019 at 18:37):
Hello @Lloyd McKenzie . I wanted to please ask for further clarification. Imagine there is an extensible binding strength value set that has values A, B, C, D, and E. But my implementation will only accept C, D, and E. Can I constrain the value set to just C, D, and E while still keeping binding strength at extensible? Or would I have to support all the values that were in the preferred value set? Or would I have to change the binding strength to a tighter level of constraint (for example, required)? Thank you!
Lloyd McKenzie (Apr 08 2019 at 21:09):
When you say "my implementation will ony accept C, D and E", does that mean that you won't accept other codes of any sort, nor will you accept just plain text? If that's the case, then you should have a "required" (not 'extensible') binding to C, D and E - and that would be completely conformant. If you were willing to accept other codes or plain text as well as C, D and E, then you could have a constrained extensible binding, but that wouldn't override the original binding. I.e. in a situation where A applied, the A code would still have to be sent - you couldn't send another code or plain text where A applied without sending A.
Last updated: Apr 12 2022 at 19:14 UTC