Category Archives: v2

Question: Positional location of OBX-3 codes and AS 4700.2

Question:

I have LOINC codes in OBX.3-1, OBX.3-2, OBX.3-3 for most of my results and then I have a result that I have no LOINC code for. Do I place a local code in OBX.3-1, OBX.3-2, OBX.3-3 or do I leave them blank and put it in OBX.3-4, OBX.3-5, OBX.3-6?

e.g. usually it would be this:

|2896-8^SODIUM^LN^K^SODIUM^NATA[NNN]|

and should I have

|WEIRD^MY WEIRD TEST^NATA[NNN]|

or

|^^^WEIRD^MY WEIRD TEST^NATA[NNN]|

Answer:

OBX-3 is of type CE. in v2.4 (AS 4700.2 is based on v2.4), the CE data type definitions says:

Components 4..6 are defined analogously to components 1..3 for the alternate or local coding system. If the alternate text component is absent, and the alternate identifier is present, the alternate text will be taken to be the same as the text component. If the alternate coding system component is absent, it will be taken to mean the locally-defined system

OBX-3, on the other hand, says:

When local codes are used as the first identifier in this field we strongly encourage sending a universal identifier as well to permit receivers to equivalence results from different providers of the same service (e.g., a hospital lab and commercial lab that provides serum potassium to a nursing home). LOINC® is an HL7 approved code system for the Observation identifier.

That’s kind of a dollar each way then, as to whether the locally defined code system goes in 1-3 or 4-6. In the context of AS 47002, this is cleared up by the implementation handbook, which says:

Example:
LOINC: |6300-8^Glucose^LN| ‘LN’ is the HL7 indicator code for LOINC
Local: |Na^Sodium^NATA1234| 1234 is the NATA# for a laboratory.
Local: |Na^Sodium^NATA1234-7| Ditto except using version 7 method or format
Laboratories may provide both the local and the LOINC codes and descriptions.

Important: Where a code is available from a public terminology such as LOINC or SNOMED-CT and a local code the public terminology should come first as in the example above. Where both a LOINC and SNOMED code is sent then the LOINC code has to be in the 1st triplet. Where two codes are sent they must be codes for the same concept. (from 13.21)

So the answer is definitely to place the local code in components 1-3 when there is no LOINC code.

 

Question: HL7 v2 case sensitivity

Question:

Are segments in an HL7 message case-sensitive….Example; if I change it from MSH to msh will the message still go through

Answer

Yes. Segments are case sensitive. most parsers will not accept a lowercase segment (in fact, none that i know of).

Generally, all other fixed values in the standard should also be treated as case sensitive unless you are specifically told otherwise.

Problems with PBS codes

The Australian PBS codes are used to describe the medications for which the Australian government offers rebates under the Australian Pharmaceutical Benefits Scheme. The codes are published as part of the rules definitions tables, and can be found here. In living memory, the codes have consisted of 4 digit codes followed by a alphabetical check letter. For instance, the code for a particular packaging of Simvastatin (used to be a clinical interest of mine) is “2011W”, and you can get the full details for this code at http://www.pbs.gov.au/medicine/item/2011W (note that this is not case sensitive, and http://www.pbs.gov.au/medicine/item/2011w also works).

However, the 4 digit codes are starting to run out. As I previously discussed, the PBS team won’t be reusing old codes for new meanings, so that means that they’re going to start using longer codes. That’s forecasted to happen in May/June this year.

That’s where the fun starts. From my post from before, the proper representation for a PBS code in a CDA document is this:

<code code=”1471K” codeSystem=”1.2.36.1.2001.1005.22″/>

and in a v2 message, it would be something like this:

 |1471K^^PBS|

(Though there’s no v2 registered code system for PBS – I’d like to think that means that no one is exchanging PBS codes in v2, but I think people are. We talked about defining PBS on an Australian basis, but we never formalised that)

The problem

However there’s a problem: when Medicare were updating their systems to handle longer PBS codes (something that was done last year after it was decided that PBS would use longer codes), they changed their interfaces so that the PBS code would be represented like this (quoted from one of several rules published as amendments to the National Health Act):

PBS/RPBS Item Code: Six bytes, right justified, zero filled, five bytes numeric followed by one byte alphabetic check character, being the code for the pharmaceutical benefit which appears in the Schedule of Pharmaceutical Benefits for Approved Pharmacists published by the Department of Health and Ageing. A zero code is to be used in the case of Repatriation items which are not included in the Schedule but have been prior approved by the Department of Veterans’ Affairs.

Valid values include: 0-9, A – Z. Alpha character must be in upper case.

So all the DHS/Medicare interfaces prefix the PBS code with a 0, like this: 01471K. Note that many of the medicare interfaces are fixed width file interfaces, and they don’t really have a lot of choice but to fix the width of the field, and it’s going to be either prefixed with spaces or zeroes.  Whatever,  the PBS Authority (DOHA) that publishes the codes doesn’t prefix with 0.

I discussed this with the team that defines the PBS codes. From their point of view, the code is an integer value, with an accompanying check character, and whether or not the integer value has any ’0′ digits prefixed to it is not significant, doesn’t affect the check digit calculation, and doesn’t affect the interpretation of the code. Whether 0 is prefixed in any given context is an implementation detail, and they are comfortable with people using either form.

Note that they don’t use prefixed codes – the ascii and xml formats that they distribute don’t include a leading 0, and http://www.pbs.gov.au/medicine/item/02011W is not found (based on the links above). That’d be the implementation aspect of it showing up.

As a side note, the PBS codes already include 2 and 3 digit codes for some special items. For instance, 183P is Chlorhexidine Acetate   (use as additive only). Note that no variation of http://www.pbs.gov.au/medicine/item/183P that I could think of trying worked, so I presume that these special codes are not published through the PBS web site. Btw, they PBS team also informed me that they reserve the right to use codes longer than 5 digits in the future, but I think we can safely assume that this won’t happen since DHS can’t support it without changing their interfaces again, which isn’t going to happen any time soon.

Because one of the first document types to be uploaded to the pcEHR was the medicare records, and because they use the 0-prefixed form internally, naturally, the medicare documents contained this form:

<code code=”01471K” codeSystem=”1.2.36.1.2001.1005.22″/

And because of the way this is implemented internally in the pcEHR, the pcEHR is therefore configured to only accept the 0-prefixed form. And now vendors that are testing to their documents with the pcEHR are running into this as a problem, since they do not prefix the existing codes with 0s.

Solution

There are various possible solutions:

  1. Get DHS/Medicare to change to not prefix the codes with 0
  2. Insist that PBS codes are always prefixed with 0 values to 5 digits when they are exchanged between systems (but not displayed to users?)
  3. Leave it that all systems should accept codes prefixed with 0s or not and know that the code itself is the same either way
  4. Say that the medicare interfaces and the pcEHR documents always (and must) prefix with 0, but in other contexts, it doesn’t matter (see rule #3)

I think we can safely say that the first isn’t a good idea. The second sounds like a good idea unless one day we start using 6 digit codes, but what happens to existing interfaces? #3 sounds like a good idea, but is really tough for systems, since the codes are suffixed with an alpha character – this violates normal rules for handling code systems, and special cases are always bad. The 4th is a variation of the 3rd that spreads the pain around differently (still involves special cases).

It doesn’t seem obvious to me what is the right solution here. This blog post is to solicit opinions from the various vendors etc that are affected by this problem. You can either comment on the post here, or if that is counter to your policy, you can comment to me directly. (Note that if you have a relationship with NEHTA, and it’s necessary, you can comment to me under NDA if you wish).

At some stage I’ll have to update the registration for the code system to clarify this, but I’ll wait for now. Also, I think it’s probably necessary for us to get a v2 code system for PBS codes. Let me know if you exchange PBS codes in v2 messages.

Update (13-Feb 2013): DHS advises that: “PBS Online will accept either a zero-filled or non zero-filled PBS item code. In practice some Software Vendors zero-fill and some do not.”

Question: HL7 v2 Query Semantics

Question:

My question relates to HL7 v2 Query / Query response. In chapter 5 of the specification, it talks about a query and its response should be thought of as a message pair. Does that mean when a server responds to a query it should only respond with information pertaining to the query?

I ask because we are interacting with a service that can respond to a query with information from a previously timed out query in addition to the current query.

Would you consider that a breach of HL7?

Answer:

It’s certainly true that the expectation is that the query and response are a pair. Well, at least, that they are tied together. A single query may lead to multiple responses. Concerning the use of these messages, the specification says:

The variety of potential queries is almost unlimited

These transactions provide a format, or a set of tools to support queries to the extent desired by the institution. The resources available and local policies will influence the type of queries that are implemented

(Both quotes from section 5.2)

I wonder about the wisdom of responding to a new query with information from a previous query, but it’s certainly not a “breach of HL7″ (i.e. not conformant).

Question: Special Characters in HL7 v2

Question:

Can Hl7 v2 messages contain any special characters in them?

Answer:

A standard v2 message is restricted to ASCII characters in the range 32 to 126. Some of the characters need to be use for syntactical separators, and so there is special support for escape sequences to represent these actual characters in the message. But these sequences don’t support special characters.

To support special characters, you can do one of two things:

  • Use a unicode message (i.e. UTF-16). Note that using unicode can only be done by trading partner agreement, and not many systems support unicode (mostly they are still ASCII back ends, though unicode support is wider in Europe and Asia than in primarily english speaking countries, where systems are migrating to unicode very slowly)
  • Use a character escape sequence – \M or \C. These are even less supported, and not well understood (see chapter 2 of the v2 standard)

Alternatively, you can just pretend that a code page agreement has been made, and use ascii characters in the range 127 – 254. This is infrastructurally easy, but hard to manage – code pages are poorly understood, often unmanaged, and translation between them is often impossible.  (Naturally, then, this is what I see most often in practice)

 

Question: How are alerts exchanged in v2?

Question:

How are “High Risk Alerts” communicated between HIS and PACS? If there is a ‘High Risk Alert’ created for patient (ex . Pace Maker), in which HL7 Message should be communicated to PACS?

Answer:

There’s nothing explicitly defined for this kind of alert in HL7 v2 so far as I can see. The segment IAM is for “Patient adverse reaction information” (defined in v2.4) and could definitely carry related information around alerts, but not that kind of alert.

If it was up to me, and given the context of HIS –> PACS communication, which pretty much implies ADT, I’d use the OBX segment for Observation/Result that appears in most ADT messages. I think that’s within it’s intended purpose, though information about the purpose of the OBX segment in the specification itself is pretty thin.

 

Understanding v2 Acknowledgements

Almost always, when you send an HL7 v2 message, you need or get an acknowledgement message back from the destination system. This post describes how these acknowledgements work.

Scenarios

There’s 2 main uses for acknowledgement messages:

  • You need some content returned from the destination (i.e. accepting an order, getting an answer to a query)
  • You simply need to know that the message was received and processed without error

There’s a few corner cases where you don’t even need acknowledgement – the sender simply doesn’t care whether the receiver gets it or not. In the real world, the only case that I’ve seen for this is a vital signs monitor that sends an observation message with the current vital sign measurements once every minute. It’s assumed that some other system will raise an alert if the messages aren’t getting through. In every other case I’ve seen, there’s some kind of acknowledgement.

Response message

Each HL7 v2 message Event has a defined message type, and also a defined response message type. The most common response message is the simple ACK message:

That’s the v2.6 version, with the SFT and UAC segments that I’ve never seen in production. Otherwise, it’s got a message header (MSH), the MSA segment, which summarises the acknowledgement status of the message, and it may have one or more ERR segments that list specific issues in the message. I have seen ERR segments in production, but not often.

There are response messages with a much more complicated structure, such as the response to an R02 event, which is a full blown order message with an MSA added – a query for an order. In this post, I’m solely going to deal with the issues around message level acknowledgements.

MSA Segment

The MSA Segment has the following fields:

 # Description Data Type Table
1 Acknowledgment Code ID: Coded Value for HL7 Defined Tables Acknowledgment code (0008)
2 Message Control ID ST: String Data
3 Text Message ST: String Data
4 Expected Sequence Number NM: Numeric
5 Delayed Acknowledgment Type -: withdrawn
6 Error Condition CNE : Coded with No Exceptions Message error condition codes (0357)

The first field contains the acknowledgement code, where the possible values are:

Code ID Description
AA 1 Original mode: Application Accept – Enhanced mode: Application acknowledgment: Accept
AE 2 Original mode: Application Error – Enhanced mode: Application acknowledgment: Error
AR 3 Original mode: Application Reject – Enhanced mode: Application acknowledgment: Reject
CA 4 Enhanced mode: Accept acknowledgment: Commit Accept
CE 5 Enhanced mode: Accept acknowledgment: Commit Error
CR 6 Enhanced mode: Accept acknowledgment: Commit Reject

I’ll discuss the enhanced mode acknowledgement below. So you can receive 3 different kinds of codes:

  • Accept – the message was accepted without error
  • Error – the message had an error and was rejected
  • Reject – the message was rejected because of an error

I’ve always wished that there was some consistent difference between “error” and “rejection”, but I’m not at all sure what it is. In fact there’s no particular definitions of these two concepts. The best I can find is that a reject (CR) is returned if the one of the values of MSH-9-message type, MSH-12-version ID or MSH-11-processing ID is not acceptable to the receiving application, and an error is returned if the message cannot be accepted for any other reason (e.g., sequence number error). However this is rather confused by the table of values for MSA-6:

Code ID Description
0 1 Success: Message accepted
100 2 Error: Segment sequence error
101 3 Error: Required field missing
102 4 Error: Data type error
103 5 Error: Table value not found
200 6 Rejection: Unsupported message type
201 7 Rejection: Unsupported event code
202 8 Rejection: Unsupported processing id
203 9 Rejection: Unsupported version id
204 10 Rejection: Unknown key identifier
205 11 Rejection: Duplicate key identifier
206 12 Rejection: Application record locked
207 13 Rejection: Application internal error

I don’t know how to make systematic sense of this. If the database is down, so you can’t accept the message, should you return an error, or a reject? Beats me. And in practice, implementers seem to pretty much toss a coin. I think I’ve seen more AEs than ARs, on about a 4:1 ratio.

Processing Failures

I find this particularly frustrating because the question I always need to ask when I get an AE or an AR back is simple: should I send this message again?

In practice, the single most common cause of a message error/rejection being returned is some transient system error. Things like:

  • database is down / backing up
  • message handling process has become corrupt
  • deadlock contention
  • network unavailability

In all these cases, the correct thing to do is wait a while, and resend the same message again, and to keep doing so until it succeeds. If, on the other hand, the destination is working as expected, and there’s some content problem with the message, then what you want to do is to discard the message, make an entry some error log, and move on. So how can you tell the difference? Well, there’s no general method, and quite often, you can’t. I think this is one of the worst aspects of HL7 v2 messaging.

As a follow up to this, there’s a related question: do I need to send the messages in order or not? This is also a rather difficult question. There’s no technical requirement anywhere in the HL7 standard I know of that says that messages have to be delivered in order, but the messages reflect a series of transactions, and these generally do need to be delivered in order. Consider the following scenarios:

  • An ADT feed pushing patient and episode updates out. What happens if you drop a patient merge message, and then send it later, after other transactions on the patient record? (and in practice, merge messages are particularly prone to cause issues)
  • A results feed from a lab to an EHR. Lab results are amended periodically. What happens if you hold a message, and then release it – will it overwrite an subsequent version of the same lab report that was sent later?

In practice, this depends on the fine details of the identity and timestamp processing of the receiving system. HL7 has made no rules about how this works, so you can take nothing for granted. In practice, most v2 processing feeds are unreliable and fragile in this regard, whether from big or small vendors (that’s my experience) so it’s best to be very conservative unless you specifically know otherwise : If you get an error, hold everything until some knowledgeable human intervenes. Assuming, of course, that there is one available… where as there very often isn’t.

More

I’ve run out of time for now. I’ll make a follow up post that deals with enhanced mode acknowledgements, with the impact of intermediaries, and with a commentary about the sequence number protocol.

 

 

 

MSIA’s Clinical Messaging Profile

Yesterdays’s post about Healthlink’s Messaging Quality Initiative created some email chatter, and I need to issue a couple of clarifications. But I should also explain the process:

The MSIA Process

In late 2010, it became obvious that the Australian Governments’s various initiatives that focused on more secure, robust exchange that was intended to make it easier to exchange content with any healthcare participant would require more robust interoperability at the content level. This underlying cause manifested in the impact that SMD would have on the existing content distribution networks. The way they currently work (roughly) is that they transfer HL7 v2 messages from source to destination, but while doing so, they consult a large lookup table to compare source and destination systems, and see what changes they need to make to the message actually work. Changes are required to work around differences in:

  • Message parsing
  • Message routing and storing
  • Content Processing and Presentation

Some of these things are utility/functionality, but some are basic clinical safety considerations.

As a consequence, MSIA invited any interested vendors – the source systems, the destination systems, and the guys in the middle – to discuss the problems, and come up with solutions, with the intent that all the MSIA members would be required to change their systems to implement the agreements. The overall goal was to remove the need for messaging vendors to modify the messages as they transfer them.

The initial problem list was primarily contributed by Medical Objects, who were enthusiastic participants. Other participants included Kestral (my employer at the time), Healthlink, Genie Systems, Healthscope, AHML, DCA, Queensland Health, Argus, Global Health, Totalcare, Medisecure, Medinexus, and Smarthealth. (If you participated, and you’re not on the list, you didn’t make the minutes, sorry).

The outcome of a couple of meetings over a 3 day period was a report describing the problems and their agreed solutions. This was prepared by Vince Macauley on behalf of AHML/MSIA, and distributed internally to the participants.

I volunteered as a follow up to rewrite the report as a formal message profile with conformance points. This hasn’t gone anywhere, and is what I posted yesterday.

In terms of outcomes, the process hasn’t really ever come to completion. I know that several vendors did make changes to align with the decision that were made, but I suspect that the overall impact has been pretty minor so far. On the other hand, the decisions that were made have been fed back into the standards process for future versions of the AS 4700 standards, and have also informed and influenced decisions on the same or similar issues in the NEHTA specifications.

My Clarifications

Firstly, while Healthlink participated in the MSIA consensus process that defined the clinical messaging profile, they did not lead or initiate it. And, while I’m at it, Healthlink’s initiative wasn’t particularly focused on the MSIA profile, just on standards generally. It’s me that made that link.

Secondly, while I volunteered to write the profile, this was editorial work. The decisions it represents, and any authority it has, are vested in the consensus process shared by the participants. The important parts aren’t my work, and I wasn’t intending to claim otherwise.

Healthlink’s Messaging Quality Initiative

From the ever excellent Pulse-IT:

Electronic messaging provider HealthLink has launched a campaign to encourage electronic medical record (EMR) and practice management software companies to improve the quality of electronic messaging.

Tom Bowden from Healthlink spoke to me about this yesterday at the HIC conference. I thoroughly endorse this initiative – we need much better compliance with “standards” to make messaging safe, and there’s no question that it needs to be safe. But what standards? Quoting from the article:

He said these examples showed the importance of ensuring consistent implementation of messaging standards, in particular the correct and reliable use of HL7 message acknowledgements.

Yes, in particular, we need to get everyone to correctly and reliably use HL7 message acknowledgements, though this is more difficult than it sounds since “correct and reliable” use of acknowledgements is not very well understood or even defined in the HL7 standard. Actually, it would be an improvement just to have all vendors actually using acknowledgements at all, let alone correctly. I’ll make another post shortly about the ins and outs of using acknowledgements correctly.

So what other things are included in the not-particularly part they are going to be looking at? Well, Tom indicated that they were looking for conformance to AS 4700 standards – but we know that they don’t go far enough – there’s still known clinical safety and implementation issues with messages that conform to the standards. Because of this, a couple of years ago the MSIA developed a clinical messaging profile that covered the common issues.

I drafted the profile, but it seems to have fallen off the priority list at the MSIA, and I don’t know why – it’s very important. Since I’m frustrated with the lack of process, I’m posting the draft here:

Draft MSIA Clinical Messaging Profile

Alert – this is a draft, and MSIA needs to finalise this. Conformance to this will resolve many of the known safety issues. The intent from MSIA was that all members would be required to implement this by last year. Obviously, the time line has lagged badly, but we need to do this: the current message delivery systems are not safe.

Note that Healthlink participated in the work that lead to this profile, and Tom indicated that they were interested in including this work in their register.

What about CDA?

Someone asked me yesterday why we should spend time on fixing v2 messaging, when all this would be resolved by using CDA, especially given that many of the vendors have now implemented a CDA handling infrastructure, and there’s a NEHTA e-Referral specification. And I do think that adopting the CDA stack would resolve all these issues – I have argued this before. But adopting the whole CDA stack is a large piece of work, and it’s not going to happen quickly. In fact, the diagnostic industry has no intent to adopt CDA, in spite of the evident advantages. As long as message senders are stuck using v2 – and I assume this will be for at least a decade yet – then we need to fix v2. This is only pathway I’ve seen to address these issues.

If you believe that we should have clinical safe messaging, then you need to push your vendor / your industry organisation / college to get this profile finished and adopted.

 

Question: How to populate OBX-23?

Question:

I am working on creating a reportable labs HL7 message and am having great difficulty finding information on how to complete the OBX-23 component of the message

Answer:

OBX-23 is the Performing Organization Name of the laboratory. It has the following fields (v2.6):

ID Name Data Type Table Table Values
1 Organization Name ST: String Data
2 Organization Name Type Code IS: Coded Value for User-Defined Tables Organizational name type
3 ID Number NM: Numeric
4 Identifier Check Digit NM: Numeric
5 Check Digit Scheme ID: Coded Value for HL7 Defined Tables Check digit scheme
6 Assigning Authority HD: Hierarchic Designator Assigning authority
7 Identifier Type Code ID: Coded Value for HL7 Defined Tables Identifier type
8 Assigning Facility HD: Hierarchic Designator
9 Name Representation Code ID: Coded Value for HL7 Defined Tables Name/address representation
10 Organization Identifier ST: String Data

There’s some somewhat confusing stuff here, a fusion of naming and identifying an organization. Here’s my notes about the components of this data type:

  1. Sounds simple – the name of the organisation. But organisation names are slippery beasts, and subject to change. So there’s a lot more information to add to deal with the ins and outs of this
  2. The type code can be Alias, Display, Legal, or a stock exchange code (not sure what the use case for that is). This isn’t that useful in OBX-23 where you can only have one name. Most likely, the systems doesn’t know what kind of name the use entered, so it can’t populate a value. And you should only put a value in here if you *know* what the right value is
  3. Components 3-8 match the equivalent components 1-6 of the CX data type, and represent *one* identifier that identifies the organization. i.e. you can have one name and one identifier. But see notes about component 10 – this component should not be used
  4. Identifier check digits should not be used.
  5. Identifier check digits should not be used
  6. This is the identity of the authority that issued the identifier in component 10. Typically, you have either a public identifier (preferred) or a private key there. This component scopes the identifier by providing a code (in sub-component 1) or a more formal identifier in sub-component 2. Sub-component 3 provides more information about sub-component 2. It’s hard to provide general advice about the HD data type. If you are using an identifier issued by a public authority, there should be some advice somewhere about how to properly identify a particular authority. I say *should* because I have no idea where to look outside Australia (and here in Australia, my earlier blog post about this eventually developed into a hand-book to be published soon by Standards Australia)
  7. The type of the identifier – if known. Only a few of the values in the table are applicable to organisations, such as NII, and the ubiquitious but uninformative default “XX” (Organization identifier)
  8. Where (place or location) that the identifier was assigned. Usually this is not known, and mostly this is irrelevant, and I’d advise against using it.
  9. Don’t use outside Japan
  10. This component replaces component 3. I don’t recall the discussion around this component, but the only apparent change is the type – that component 3 should have been ST, not NM, and this replaces component 3 with a type of ST, to better align with CX

So, summary: org name in component 1. Only populate 2 if you’re sure. If you have an identifier, put it in component 10, and then populate 6 with a scope for that identifier. Populate 7 if you’re sure. Leave everything else blank.