Convert your FHIR JSON -> XML and back here. The CDA Book is sometimes listed for Kindle here and it is also SHIPPING from Amazon! See here for Errata.

Thursday, July 20, 2017

Date queries as offsets from now in FHIR

It's fairly common to ask questions about time in relationship to now.  Have you had a mammogram in the last 12 months?  What medications was the patient given today?  What are the labs for the last 30 days.  Can we schedule a visit for a month from now?

When a date query is expressed in the form of a simple quantity, there are two pieces of information given: A value, and a unit of measure in duration.  When expressed as FHIR queries, a date and a simple quantity are quite readily discernible.  Dates have -, : or T punctuation in them.  Simple quantities have units and | punctuation.

So I decided to try this out mentally.  One of the challenges is dealing with precision.  If someone asks me what I've did last month, I'm thinking June.  If they ask me what I've done in the last month, mentally I'm thinking July and the end of June, because I mentally translate to 30 days or so.  But then if they ask me what I was doing more than a month ago, I go back to thinking in one month chunks, so before June.

I decided that units specified in the query would also specify the units of precision.

I adopted the convention that a date query parameter named "date" would have an alternate way of specifying it using the name "date-fromnow".

So, if you query from date-fromnow=le-1||a what you would be asking is "what happened in the year before the last one." That's equivalent to date=le2016.  If you wanted more precision, you could ask in months or days (weeks are a bit messy, so I didn't deal with them).  Thus, date-fromnow=le-12||mo means date=le2016-07.  And date-fromnow=le-365||d means date=le2016-07-05.

Good enough.  Time to go implement this and see how it pans out.


P.S. For what it's worth, this is quite useful to implement some of the guidance in the Relevant and Pertinent work that was done=-1||a.

Wednesday, July 19, 2017

How do you write a blog?

I get asked this question a lot.  The answer of late is that I haven't been, but I'm getting back into it. This is my fourth post in five days, back up to my previous rhythm when I was at top of form.

There are three big issues:

  1. Time
  2. Topics
  3. Trepidity (bordering on Terror)


Where do you get time to write?  A lot of the topics I write about are things I'm already spending time on.  Taking what I'm working on and turning into a blog post is a lot easier than writing a post specifically for this blog.  It takes 10-15 minutes, and in the end, I have more clear thinking AND a blog post.  
Allocating time to write is critical.  It doesn't need to be at a fixed time each day (or week or whatever frequency) is important.  It takes discipline.  Make the commitment, and then execute. 

After you've been repeatedly writing a post on a regular rhythm, you will find it takes much less time. When I first started this blog, I might have spent an hour or even two on a post.  These days, it takes much less time.

In summary, use what you are already doing, make the commitment, and give it time to improve.


I get my topics a number of ways: Standards projects, mailing lists (a good e-mail response to a list group can also be a good starting point for a blog post), news articles, my Ask Me a Question page, and sometimes, just staring at a blank screen.  When a good topic comes to mind, I write it down for future use.  I don't have a big future pipeline, maybe one or two ideas at most.

Yesterday's post on Building Blocks was essentially me thinking out loud about my position on interop building blocks.  I took an item I was already working on for my own needs and repurposed it for something else.  The post on vocabulary started from an email on an HL7 list.  This post today started from a question someone asked me that I've had asked before (always a good sign that a blog post might be warranted).

That blank screen is is a challenge.  Some days you'll be in that time for writing a post, and have NO topics.  I just start writing and see where the flow takes me (those are usually tagged Rambling).


Not really a big issue for me, never was.  But I understand performance anxiety, and writing a blog is kind of like performing. The basic issue is that you need to finish strong. In any performance, the audience may notice a small bobble, but the reality is that if you finish well, few will remember your mistake, and most will remember your finish.  Don't be afraid to make a mistake. That's how you learn.  Fix it and move on. People will remember the good stuff.  If you write a terrible post, write a better one next time.  If you stop writing because of a terrible post, the first thing people will see is that post on your blog.  Write another one.

A blog doesn't need to be great, it just needs to consistently good. The best way to get there is to do it.

Tuesday, July 18, 2017

Building Blocks

If you are like me, you probably had a number of different "construction" toys growing up.  I had Tinker Toys, Lego blocks, Lincoln Logs and an Erector set.  In fact, I still have the Lego and Erector set, although they don't get much use any more.  Mostly because I get enough time to construct cool stuff for my day job.

I ran across this video this morning.  You can probably relate.

These are my building blocks today:

  • CDA Templates
  • FHIR Resources (and Argonaut Profiles of them)
  • IHE Cross Enterprise Document Sharing Family of Profiles
    • XCA, XDS, XDR and XDM
  • IHE Mobile Access to Health Documents (MHD) [Basically a FHIR replacement for the above]
  • OAuth2
  • TLS
  • FHIR Audit Resource
I've done CDA to FHIR transformation and visa versa, CDA to XD*, XD* to MHD and MHD to XD*, and mapped ATNA to the FHIR Audit Resource.

I have the "adapter kit", and I've also built some adapters for X12 and HL7 V2 (a whole chapter of the CDA Book is devoted to V2 to CDA transformation, and I've also done the reverse).

Each of these "building block kits" has a slightly different way of doing things, but since they were built incrementally, usually with knowledge of at least one predecessor, there's some clear backward compatibility built in [although not exposed to those unfamiliar with the history of these works].

If you want to put wheels on something, there's a Lego way to do that, or a Tinker toy way, or an Erector set way (I haven't really figured out how to do it with Lincoln logs yet), and the same is true for my "adult set" of toys.  And just because I can do the same thing with both, the amount of effort invested varies.

FHIR is extremely promising as a way forward, because it continues to incorporate the learnings from previous efforts.  But we aren't all the way there yet.  I have a significant investment in Lego, and it's wickedly cool and easy to put together.  But it doesn't quite have the strength to span long distances with great weight reliably and at the same cost per piece the way that an erector set does (but I suspect it will get there).

  1. Will we get there?  Eventually I think we will.  
  2. But we've also had Highlander for 30 years.  Have we reached only one yet?  No.
  3. Is it going to happen soon?  Yes.  
  4. Soon enough to make everyone happy? Surely not, because that would have meant we had reached that point a decade ago.

Monday, July 17, 2017

The Vocabulary of Vocabularies for the non-Vocabularist

In informatics and health IT standards circles we talk about Ontology in a way that assumes that everyone understands what that means.  Yet the ontology of ontologies is rather complex and confusing, in part because definitions are in some ways, rather "meta".

What follows are my own definitions, written to be intelligible to a software engineer without informatics or health IT standards training.

TermA word or phrase describing a thing, and associated with a concept (see Concept)
Preferred TermDifferent words or phrases can be used to describe the same thing.  A heart attack can also be described as a myocardial infarction.  The preferred term is the term for that thing that is preferred above all others.  Preferred terms are often those with the most "crisp" meaning (e.g., Myocardial infarction in the above example).
ConceptThe abstract idea associated with a thing.  This is the idea that is (intended to be) brought to mind when one uses a term to describe a thing.  A good concept has a definition associated with it that allows a user to understand the meaning of it.  In my not so humble opinion, the position of a term in an ontology is an insufficient definition because it is only intelligible to those well versed in the structure of the ontology.
CodeAn identifier associated with a concept.  It is a string of symbols (usually digits, but also can include letters and punctuation) that uniquely identifies the concept within the system using that code (see system below).  Codes can be meaningless (e.g., as used in LOINC), or can also express structure (usually hierarchy) as in ICD or the Healthcare Provider Taxonomy.
Check DigitA digit or character in the code used to enable verification that the string used as a code is valid and is not the result of some sort of data entry error.  Check digits prevent various kinds of data entry errors including deletion, insertion, and transposition.  LOINC uses MOD10, and SNOMED uses Verhoeff algorithms to compute check digits.
VocabularyA collection of terms describing things.  A good vocabulary has both the terms, and associated definitions of what those terms mean in a way that the users of that vocabulary can understand the meaning.
Value SetA managed collection of terms describing related things and associated with some sort of identifier so that it can be referenced. A value set most often contains terms from the same vocabulary system, but might include terms from multiple vocabulary systems.
HierarchyAn arrangement of things into a tree structure, such that each item (except the top-most) has exactly one parent.
Poly-HierarchyAn arrangement of things into a directed graph structure without loops, such that each item in the graph (except the top-most) has at least one, and can have more than one "parent". There may be multiple top-most items.
ClassificationA vocabulary that describes all the different things that can happen such that the description of any one thing fits into one and only one bucket.
TaxonomyA hierarchical classification; A classification that also has a tree structure associated with it.
TerminologyCustomarily, a terminology is a collection of vocabularies that can describe multiple related things.
SystemA phrase appended to code, vocabulary, classification, taxonomy, terminology or sometimes ontology.  The word system implies a process or method associated with the work. When this word is used, it implies a degree of formality associated with the development of the work.
OntologyIn this context, an ontology is a classification system that describes not only a collection of things, but can also describe the parts of itself.  Under this definition, SNOMED CT is an ontology, and so is LOINC (because some LOINC parts describe LOINC itself), but ICD is not.

Friday, July 14, 2017

Wearing Many Hats

When I first started working with ANSI/HITSP over a decade ago, one of the things I remarked upon to several people was the outstanding ability of John Halamka to wear many hats, and to make it clear which hat he was wearing when he was speaking, and his general ability to be wearing the right hat for the right audience.

It's a tricky challenge, and quite a juggling act.  I don't do it nearly as well as John does, but have been doing it a great deal over the last 18 months.  These are just a few of them in approximate rank order based on time investment (though not necessarily personal preference):
  1. Patient Advocate
  2. Architect Owner
  3. Product Owner
  4. Subject Matter Expert [Health IT Standards & Regs]
  5. Informaticist
  6. Software Developer
  7. Engineering Manager
  8. Thought Leader
  9. Student
  10. Teacher
  11. HL7 Board Member
  12. HL7 Member
  13. IHE Member
  14. Document Writer

I often find my various hats being at war with each other.  My software developer side wants to argue with my SME side, or sometimes I find my IHE side needs defending from one of my HL7 roles or ...

When that happens, it is very challenging to understand how to resolve the problem.  The pragmatist and the purist at war is not pretty.  Purism has its place, as does pragmatism.  Perfect is the enemy of the good goes to battle against applying the time to do it right as compared to the time to do it over.

How do I resolve this?  I've begun to discover that the final hidden role is that of customer advocate. That jumps to number 2 on my list.  Where Patient Advocate cannot break the tie or bring peace, Customer Advocate often can.

What roles do you play?  How do you reconcile them?

Friday, June 23, 2017

Thanks to That Person

In my first computer class, we entered our programs using a line editor, and unless we were unlucky, had a CRT to work with (although the unlucky still go stuck with the linotype).  We had a text book, some well thumbed compiler manuals on a bookshelf that were shared among the many students, and there was always, somewhere, that guy (or less often but still present, that girl), who soaked it up and knew the answers to the real tricky stuff.

As I moved into the workplace, we had CRTs still, but some had graphics capabilities, there were still tons of manuals on our shelves (and for most of us, we each had our own copy).  If you were one of the lucky ones, you got graphics.  The manuals were less well thumbed, and somewhere in the office, there was that guy (or more frequently, that gal) who knew how to find the answers.

Later, we all got to move up to 16, then 256, then 16384 colors, with 640 x 480 resolution, and then 800 x 600, and if you were one of the lucky ones, 1024 x 800 displays.  Email came to the fore. Manuals were still handy, yet there was still that person.  Sometimes they'd be in another office. You'd pick up the phone, or send them an email.  After two or three forwards and days, or more depending upon the challenge, the e-mail would come back with the answer.  And because that person had email, if they didn't know the answer, they at least knew who did.

And then came the Internet, and CD drives.  Instead of a shelf of books and a file drawer full of disks you saved because you just might need them again, there was the almighty CD.  And books were fewer.  And if you were one of the lucky ones, you had INTERNET!  And that guy or gal might be a half-continent away, and e-mail was reliable and you'd only need to way a few hours.  And he or she probably had Internet, at least at home, because they still sucked it all in, and knew where to find the answer, on the Internet, or on the CD.  Of course, you still had a drawer full of CDs, but at least it was a normal one instead of a file drawer.

Now we have StackTrace, and web sites, and volumes of data.  You can ask Google or Bing. Training is online, complete with slides and audio. that person has a blog, and a twitter account or a linked in, or all three. You no longer need to be lucky to have a laptop, though if you have a touch screen or tablet, you can probably to count yourself among the lucky.  You can read what that person has to say daily, or even listen to them or better yet watch them. That person now has fans.

I'm a fan of lot of people out there.  You know who you are.  I couldn't this person without you being that person.  Thanks.

-- Keith

Tuesday, June 20, 2017

Handling Extra OAuth2 Authentication Parameters

I'm deep into spec'ing out an OAuth 2 implementation, which means that I have to give all the detailed rules about what to do with parameters sent to the authorization endpoint of an OAuth2 server.  The question arose, what do we do with parameters that aren't recognized.  Fortunately, OAuth2 clearly resolves this issue for us (and for you):

In the section describing the OAuth2 Authorization endpoint, what OAuth2 says is
"The authorization server MUST ignore unrecognized request parameters."
There's a very good reason for this.  It allows profilers of OAuth2 to add parameters with additional specified behaviors.  You won't find the SMART on FHIR "launch" parameter anywhere in the OAuth2 spec. For those endpoints that do recognize it, they can do something useful with it.

The same thing works for unrecognized scopes.  If you don't recognize it, it isn't an error, just ignore it and it should go away (the application that sent it should be expected to behave correctly when it is ignored).

Postel's law rules.

Wednesday, June 14, 2017

Thinking about Client Application Configuration for OAuth2 Authorization Grant Flow

In trying to understand how to implement the OAuth2 protocol, it helps to consider what both parties have to do.  It's kind of like playing chess, after you reach a certain level, you have to consider the plans for both black and white.

If you are implementing a client, you can probably get away with just worrying about your opening, but as a server, you have to think about how clients are architected.

In the Authorization Grant flow (the subset of OAuth2 supported by SMART on FHIR), the client has three different components that need to work with the server's two endpoints.

  1. The "login" component of the client provides the user's experience for interacting with the server, supporting the servers ability to request login credentials, authorization and in SMART on FHIR, patient selection UI.  
  2. The application service component is responsible for taking the authorization grant (or auth code) and converting in into an access token for the remainder of the work it needs to perform.
  3. Finally, the redirect URL endpoint is the piece in the middle that acts as the glue between the user interface at the front-end, and the service component under the covers.

Thinking about these three client components as three separate but coordinating components, with different sets of capabilities makes is much clearer how OAuth2 is supposed to work, or at least did for me today.

I suppose if you've actually implemented an OAuth2 client first this would be obvious.  Duh.  I'm not always smart the first time.

Friday, June 9, 2017

When do you need to create an IHE XDS formatCode

In the cross enterprise document sharing family of IHE profiles, one of the metadata attributes associated with a document is formatCode.  When XDS was created, we felt we needed a way to distinguish between content based on the set of business rules it adhered to.  This is more than just mime-type or schema.  It's closely related to CDA's templateId element or FHIR's profile tag.

As part of an affinity domains configuration, the governors of that domain can specify what formatCode values should be used for submitted documents, and when.

Recently a representative of a national program asked me:  Should we create our own format codes or use IHE format codes, noting that his national program had added rules to IHE profiles for which IHE had already created formatCodes.

The answer to that question is "Yes", or more accurately, "it depends."

Within your affinity domain (for which you set the policies), will you have cases where distinguishing between documents using IHE format codes and your own additional requirements is necessary?  If so, create your own format codes for these documents.  Otherwise, simply add the requirement to your domain policy that all documents must meet national requirements as well as adhere to IHE templates, and stick with the IHE formatCodes (as it is both simpler, and will require less effort on behalf of developers who already know how to use those).

Creating your own format codes, even when others already exist is perfectly legitimate.  Format codes are a way to express a concept that is needed to manage an affinity domain.  If what is there doesn't let you manage the domain, then there's nothing that says you cannot apply your own set. However, if you are smart, you will do your best to stick with what already exists when you can, and ONLY when it doesn't let you do what you need, will you do something different.


Thursday, May 11, 2017

L or l? The Ucum Liter code

Filed under stupid stuff I know.

The code for Liter in UCUM Case Sensitive is both l and L.  You can use either.

See for details.  Basically what they say:
In the case sensitive variant the liter is defined both with an upper case ‘L” and a lower case ‘l’. NIST [63 FR 40338] declares the upper case ‘L’ as the prefered symbol for the U.S., while in many other countries the lower case ‘l’ is used. In fact the lower case ‘l’ was in effect since 1879. A hundred years later in 1979 the 16th CGPM decided to adopt the upper case ‘L’ as a second symbol for the liter. In the case insensitive variant there is only one symbol defined since there is no difference between upper case ‘L’ and lower case ‘l’.
So much for using codes to define distinct meanings for atoms of this vocabulary.  Ah well.  At least they defined L in terms of l.


Friday, April 28, 2017

From $450 to 450¢

From $450 to 450¢ is a 99% savings.  That's what I recently found in reviewing my medication costs.

I recently compared prices on a medication a family member is using.  It comes in several dose forms, and strengths.  To keep the math the same, I'll call the strengths 1,2,3,4,6 and 9.  They can be taken in capsule or tablet form (but not in all strengths), or in oral (pediatric) form.  Not all combinations are available from our PBM, but most are.

Here are the approximate prices and sigs for a 90 day supply:

Strength 1 Capsule 6xDay: $13.50
Strength 2 Capsule 3xDay: $4.50
Strength 4 Capsule + Strength 2 Capsule: $17.50
Strength 1 Tablet 6xDay: $561.00
Strength 2 Tablet 3xDay: $422.00
Strength 6 Tablet 1xDay: $445.00

To be very blunt about this: What the FUCK!?

So now I've gone through EVERY prescription in the household, and so far this is the only one that is that whacked out. But like I said, WTF?

   -- Keith

Wednesday, April 26, 2017

Refactoring Standards

Code and standards (which are a special kind of code) grow with age.  When you started with your code, you had a plan.  It was fairly simple and so you wrote something simple, and it worked.  After a while you realized you could make it do something special by tweaking a little piece of it. Sometimes (if you designed it right), you can add significant functionality.  After a while, you have this thing that has grown to be quite complex.  Nobody would ever design it that way from the start (or maybe they would if they had infinite time and money), but it surely works.

The growth can be well-ordered, or it can have some benign little outgrowths, or they can even be tumorous.  Uncontrolled growth can be deadly, whether to a biological or a computer system.  You have to watch how things grow all the time.  After some time, the only solution may be a knife. Sometimes the guts of the patient will be majorly overhauled afterwards, even though fully functioning and alive.

When the normal adaptive processes work in standards, these growths naturally get pruned back.
It's interesting to watch some of the weird outgrowths of CCR become more and more vestigial over time through various prunings in CCD and CCDA.  FHIR on the other hand, well, that started as a major restructuring of V3 and CDA, and is very much on the growing side.

   -- Keith

Wednesday, April 19, 2017

Separate but Equal Isn't

Every now and then (actually, more frequently than that), two topics from different places somehow collide in my brain to produce synthesis.  This post is a result of that:

I've been paying a lot of attention lately to care planning.  It's been a significant part of the work that I've been involved in through standards development over the last decade, and it comes to special focus for me right now as I work on implementation.

In another venue, the topic of data provenance came up, and the concern that providers have about patient sourced data.  Many of the challenges that providers have is that the patient concerns don't necessarily use the "right terms" for clinical conditions, or that patients "don't understand the science" behind their problems, or that the data is somehow less exact.  My Father's use of the term "mini-stroke" so annoyed one of his providers (a neurologist who reported to him: "there is no such thing"), that it likely resulted in his failing to get appropriate care for what was probably transient ischemia, resulting in an actual stroke, which eventually lead to his ultimate demise through a convoluted course of care.

This concern about veracity or provenance of patient data leads to designs which separate patient health concerns and information from provider generated data.  Yet those same concerns initiate the evaluation process starting first with the patient's subjective experience, gathering of objective evidence through skilled examination, knowledgeable assessment of those details, leading to cooperative and effective planning.

The care planning work that I've been involved in over the past decade originated in early work on patient centered medical homes driven by physician groups, incorporated work from several different nursing communities in HITSP, HL7 and IHE, and eventually resulted in a patient plan of care design, which was subsequently evolved into work implemented in both the HL7 CCDA and FHIR specifications.

The patient's plan of care should NOT originate from a separate but equal collection of data, but rather, from an integrated, patient included approach, that does not treat the patient subjective experience as being any less valuable to the process.  Both FHIR and CCDA recognize that in their designs.  After all, if the patient didn't have any complaints, physicians wouldn't have any customers.

It's past time we integrate patients into the care process with their physicians, and keeping their data "separate" isn't the right way to go.  If my provider want's to be my medical home, he needs to remember, it's my home, not his, and we, as implementers, need to help with that.

   -- Keith

Friday, March 31, 2017

The Longitudinal Identity of a CCD

This question comes up from time to time. For a given patient, how is there a unique identifier which uniquely identifies the CCD for the patient as it evolves over time.

The answer is no, but to understand that, we need to talk a little bit about identifiers in CDA and how they were intended to be used.

Every CDA released into the wild has ONE and only ONE unique identifier by which it is uniquely known to the world.  That is found in /ClinicalDocument/id.  During the production of a clinical document, there are some workflow cases where the document has to be amended or corrected.  And so there is a need to identify a "sequence" of clinical documents, and possibly even to assign that sequence an identifier.  The CDA standard supports this, and you can find that in /ClinicalDocument/setId.

BUT... that field need not be used at all.  You can also track backwards through time using /ClinicalDocument/relatedDocument/parentDocument/id to see what previous version was revised.  And the standard requires neither of these fields to be used in any workflow.

So ... couldn't I just use setId to track the CCD for each patient?

Yes, but fundamentially, you'd be doing something that fails to take into account one of the properties of a ClinicalDocument, and that is context.  Context is the who/where/what/when metadata associated with the activity that the clinical document is reporting on.  When setId is the same for two clinical documents, the assumption is that the Context associated with the content is the same, OR, is being corrected, not that it is being changed wholesale.

The episode of care being reported in a CCD is part of its context, as is the when the information was reported.  If you want to report on a different episode of care, it's not just a new document, it's also a new context.  And that's why I suggest that setId should be different.

This is mostly a philosphical debate, rather than one related to what the standard says, but when you think about the history of clinical documents, you might agree that it makes sense.

Clinical Documents aren't "living" documents.  A key definition of a CCD document is a summary of relevant and pertinent data "at a point in time."  It's that "point in time" part of the definition that makes the CCD document a static item.

Thursday, March 30, 2017

Diagnostic Imaging Reports in a CCD

I clearly missed something somewhere, probably because I assumed nobody would try to include a document in an document after having hammered people about it for a decade. My first real blog post was on this topic.

Here’s the challenge:  According to the Meaningful Use test procedures for View Download and Transmit: Diagnostic imaging reports are to be included in CCD content.  The test data blithely suggests this content:
·         Lungs are not clear, cannot rule out Anemia. Other tests are required to determine the presence or absence of Anemia.

I can see where this summary of a full report might appropriately appear in “Results” section of a CCD document, but this isn’t an diagnostic imaging result. Here’s a some sample Diagnostic Imaging Reports:,  I’m reminded of Liora’s “This is a document” slides she uses in her Intro to CDA class, and for good reason.

The content might be stored as a text report, a word document, a PDF, or even worse, a scanned image.  It really depends on what the supplier of the report provides.

The NIST guidance is sub-regulatory, but these are the testing guidelines set forth for the certifying bodies.  However, what I also missed is that the regulation also says that CCD is the standard for imaging reports.  It's in that line of text that reads:

(2) When downloaded according to the standard specified in § 170.205(a)(4) following the CCD document template, the ambulatory summary or inpatient summary must include, at a minimum, the following data (which, for the human readable version, should be in their English representation if they associate with a vocabulary/code set):

(i)Ambulatory setting only. All of the data specified in paragraph (e)(1)(i)(A)(1), (2), (4), and (5) of this section.

(ii)Inpatient setting only. All of the data specified in paragraphs (e)(1)(i)(A)(1), and (3) through (5) of this section.

Clear as mud right?  Here's what (e)(1)(i)(A)(5) says:

(5) Diagnostic image report(s).

Oh damn.

But wait? I can create a DIR, change the document type and header details a bit, and then magically it becomes a CCD.  So, can I create a CCD for each Diagnostic image, and in that way have a "summary" representation of the report.

Nope: Back to the test guide:

3. The tester uses the Validation Report produced by the ETT: Message Validators – C-CDA R2.1 Validator in step 2 to verify the validation report indicates passing without error to confirm that the VDT summary record is conformant to the standard adopted in § 170.205(a)(4) using the CCD document format, including: the presentation of the downloaded data is a valid coded document containing:

  •  all of the required CCDS data elements as specified in sections (e)(1)(i)(A)(1); 
  •  for the ambulatory setting, the Provider’s Name and office contact information as specified in section (e)(1)(i)(A)(2); 
  •  for the inpatient setting, admission and discharge dates and locations, discharge instructions and reason(s) for hospitalization) as specified in section (e)(1)(i)(A)(3);
  •  laboratory report(s) as specified in section (e)(1)(i)(A)(4), when available; and 
  •  diagnostic imaging report(s) as specified in section (e)(1)(i)(A)(5), when available.  
Oh well.  Seems like I need to get my hammer out, this time to fit an entire document into a sentence shaped hole.

Friday, March 17, 2017

Patient Access: It's coming at you faster than you might think

This crossed my desk this morning via POLITICO:

GAO: PEOPLE AREN'T LOOKING AT THEIR ONLINE DATA: The Government Accountability Office took aim at the accessible data requirement in meaningful use in a report released Wednesday. The report, requested by the Reboot group (which include Sens. Lamar Alexander and John Thune), argues that while the vast majority of hospitals and eligible professionals make data available for patient and caregiver consumption, the percentage actually following through isn't high — perhaps 15 to 30 percent, depending on the care setting and data analyzed.
Now, why that's the case is the familiar debate — is it a lack of interest from patients, or perhaps technical difficulties? A GAO analysis suggests the former is definitely at play. The office analyzed the top 10 most popular EHRs and found patient participation rates ranging from 10 to 48 percent.

Ultimately, however, GAO hits ONC for its lack of performance measures for its initiatives — whether, for example, using Blue Button increases patient uptake of data. HHS and ONC concurred with the recommendation.

Here's my take on this.

TLDR; It isn't as bad as the GAO makes it out to be.  The report is based on nearly two year old data, and based on it and prior data, we seem to be within reach of a major milestone: 50% of all patients having accessed their data.

Remember early fax machines? e-mail? These are technology diffusion challenges which took a number of years (even decades) to get over.  We've finally reached a stage where nearly 90% of all providers are capable of offering patients their data in hospital or ambulatory settings, and now people are really getting to use this stuff.

What is the GAO report telling us?  First of all, it is telling us about events in 2015, not 2016 as you might expect.  It takes the government a while to get their act together acting on the data that they gather, and the accompanying study also took some time to set up and execute.  This is in fact why many opponents of the MU deadlines said they were coming at us too fast, because we couldn't even analyze data from prior years to figure out how to course correct before it was time to update the regulations.  We are hopefully past that stage now.

Secondly, we need to look at this in a slightly different context.  Remember I said this was a technology diffusion challenge.  If you are a long time reader of this blog, you might recall an article I wrote about the curve you might expect for technology adoption.  It's a logistic growth curve.

The GAO numbers are saying we are around 30% for ambulatory use, and 15% for hospital use of data access by patients in 2015.  Where are we now?  It's hard to project forward from one data point, because fitting the logistic curve requires estimating two parameters, a time scale, and the inflection point.  The inflection point is at 50%, and is where the rate of adoption reaches its maximum value.

To make something useful out of this data, you have to go back to some similar ONC reports on patient utilization.  You can find the data in ONC Data Brief 30, which includes information from ONC Data Brief 20.  The challenge here is that the GAO report doesn't quite report the same thing, so you have to adjust a bit.  I know from a colleague of mine from early IHE years that some patients get most of their healthcare in the hospital setting (i.e., the ER), while others get their care principally from Ambulatory providers, and others have used both.  That means that some patients have been given access through a hospital, and others through ambulatory providers, and the number of patients who have been given access to their health data is overall, probably greater than the sum of the parts, but we know these are largely overlapping sets.  So, if I simply take the ambulatory data from the GAO report, and compare the number offered access and the number who used it, to similar figures from the previous ONC briefs, I can start to get somewhere.  Here's the basic data.

Year Offered Accessed Total
2013 28% 46% 12.9%
2014 38% 55% 20.9%
2015 87% 30% 26.1%

The number offered access is different in each year, so I have to normalize the results, which I do by multiplying the % of patients offered access to the % offered access who did access data, to get the total % of patients accessing records. That's the number we really care about anyway.

Now I have three points, which is JUST barely enough to estimate the parameters of the logistic growth curve.  How to fit the data?  Well, this paper was good enough to tell me.  Basically, you compute an error function, which in the paper was least squares (a common enough curve fitting function), over the range of possible parameter values.  So I did, and generated a couple of surfaces which show me where I might find the parameters that give the best fit.  Can I tell you how good the fit is?  Not really.  I'm working with three data points, and estimating two parameters.  There's only one degree of freedom remaining.  This is about as back of the napkin hack as it gets. 

Let's look at some pictures to see what we can see here:
First up, we need to look at the error surface to find the minimum.

Error Surface

We can pretty well see it's somewhere in the lower blue region, but we have to get to a much finer level of detail to find it perfectly.  Sometimes tables are better than pictures.  The minimum is somewhere in the middle of this table.  If I expanded data points in the table even further, you'd see they are getting larger all around the area we are focused on.

0.36 0.38 0.40 0.42 0.44 0.46
Jan-2017 1.03% 0.70% 0.44% 0.26% 0.14% 0.07%
Apr-2017 0.54% 0.30% 0.15% 0.06% 0.04% 0.07%
Jul-2017 0.23% 0.09% 0.04% 0.05% 0.12% 0.25%
Oct-2017 0.07% 0.04% 0.08% 0.19% 0.36% 0.58%
Jan-2018 0.05% 0.12% 0.26% 0.47% 0.72% 1.02%

The minimum error for this fit occurs somewhere in 2017, which is also the 50% saturation point.

There's still one more picture to show.  This projects us forward along the boundaries of the fitted range.  As you can clearly see, the projections show we are nearly at the 50% point.  That's a major milestone, and something to crow about.  It also tells me that unless there's another bump to push things ahead faster, we won't get to 90% access until sometime between 2021 and 2024, five to seven years from now.  We have just such a bump (API support) coming ahead in 2018.

It isn't all as dark and gloomy as the GAO report suggests, but it might have been if that report was telling us where we were now, instead of where we were two years ago.

This is rough and ready calculation.  I'm using data that was gathered through different means, and which may not be comparable.  I don't have enough points to make any statements about the reliability of the projects.

It's still good enough for me.  It shows that things aren't as bad as the GAO report might have suggested.  ONC and HHS really need to PLAN ahead for this kind of reporting, so that we can create the dashboards needed to produce this sort of information as it becomes available, instead of 2 years after the fact.

Data reporting for 2016 is just around the corner.  Two numbers: The % of patients offered access, and the % of patients who use it if it is offered will be enough to tell me how good my projection is for now. If those two numbers multiplied together come anywhere between 30 and 40%, I'll feel very comfortable with this projection.

Thursday, March 16, 2017

I got my Data

A while back several of us HIT Geeks and e-Patients were having a discussion about HIPAA, patient data access challenges, et cetera.  Prior to that I had written a post connecting the various dots between HIPAA, the Omnibus rule, MIPS and MACRA, and the Certiufication rule.

In that conversation I accepted an implicit challenge to get my health data via unencrypted e-mail.  I wrote to someone at my healthcare provider organization in early January and then got caught up in various meetings and never followed up.  Two days later I had gotten some resistance.  My healthcare provider has a portal, which I use and can quite easily get my data already, and in fact often do, which was probably another reason for resistance.

When I finally responded in early February with my acknowledgement of the risks and the fact that I understood them, I got my data the very next day.  I'd made my point.  Two emails and I had it.  Any delays in getting it were my own fault for not following up.

Caveats: I have a good relationship with my provider organization, and also know important thought leaders in that organization and they know me.  I was able to make points others might not be able to. But, when breaking trail, it's usually a good idea to put the person most experienced at it out in front, yes.  And that's where I was and what I did.

  -- Keith

Wednesday, March 15, 2017

Principle Driven Design

When you need to get something done quickly, and it's likely to involve a lot of discussion, one of the tactics I sometimes take is to get everyone to agree upon the principles which are important to us, and then to agree that we will apply those principles in our work.

It's quite effective, and can also be helpful when you have a solo project that is confused by lots of little different relationships between things.  If you work to establish what the relationships are in reproducable ways, and connect them, what you wind up with is a design that goes from a set of principles ... or even, simple mathematical relationships.  And the output is a function of the application of those principles.

It works quite well, and when things pop out that are odd, or don't work out, I find they are usually a result of some principle being applied inappropriately, or that your data is telling you about some outlier you haven't considered.  When HL7 completed the C-CDA 2.1 implementation guide in 6 weeks (a new record I think for updating a standard), we applied this tactic.

Having spent quite a few weeks dealing with the implementation details, I can tell you that it seems to have worked quite well.  And my most recent solo foray into obscure implementation details was also completed quite quickly.


Friday, March 10, 2017

Art becomes Engineering when you have a Reproducable Process

The complaint that software engineering isn't really engineering because each thing you make is often its own piece of art is often true.  But the real art of software engineering, isn't making one-offs.

Rather, it is figuring out how to take simple inputs into a decision making process that generates high quality code in a reproducable way.

I often build code that is more complicate then if I just wrote it because I take the time to figure out what data is actually driving the decision making process that the code has to follow.  Then I put that data into a table and let the code do its work on it.

When the process has been effectively tested, adding more data adds more functionality at a greatly reduced code.

This same method is, by the way, how FHIR is built.  FHIR is truly engineered.  The art was in developing the process.


Wednesday, March 8, 2017

Monitor your "improvements"

Sometime last year, to better manage my blog I thought I would try out Google+ Comments on it.

It turned out to be a disaster on three fronts:
1.  I could no longer delete inappropriate comments.
2.  Comments must have a Google+ account, a restriction I find inappropriate on this blog.
3.  I no longer received e-mails about comments on the blog, which has now put me six months behind answering questions I didn't even know where being posted.

All of that because I failed to monitor the impact of what my "intervention" did.  Don't I know better? Yes, I do.

Year before last I recall an presentation by AMIA by Adam Wright, PhD and fellow alum of OHSU on how changes to clinical decision support system resulted in a failure for certain notifications, and thus be acted upon.  While I cannot find the paper, a related poster is here. One of my favorite classes at OHSU was on how to measure the impact of an intervention quantitatively.

I should have been able to detect the low volume of questions, but didn't.  Fortunately in my case, I just failed to get feedback and had reduced capacity to use my blog.  That situation is now corrected.


Wednesday, February 22, 2017

Transforming from a fhir:identifier to V3:II

So this blog entry has been sitting here waiting for me to post something about how to transform FHIR Identifiers into CDA II elements in a way that works 100%.  The DocumentReference resource has an example that shows this content:

  <system value='urn:ietf:rfc:3986'/>
  <value value='urn:oid:'/>

What this content means is that the master identifier for the document being referenced is a URI as defined by RFC 3986.  For CDA geeks it should be obvious that the above implies that the content of the CDA document would have this in it:

   <id root=''/>

But what about other URIs?  Well, if the URL format is urn:uuid:some-uuid-string, that's also pretty straight forward.  The output for id is simply:

  <id root='some-uuid-string'/>

OK, good.  What if the value is some other form of url?  What do we do now?  Grahame fixed this one for us by registering a new OID.

  <id root='2.16.840.1.113883.4.873' extension='some other form of url'/>

So, great, now we know how to handle all the cases where identifier.system = 'urn:ietf:rfc:3986'

What about the rest of the possibilities?
There are only three URLs you need to map to an OID described in the FHIR Identifier registry.  You can set up those lookups in an XML file somewhere.

How then, would you map an identifier containing a url in root whose corresponding OID you don't know?

There are three ways to handle this case:
1. Come up with something that produces a valid II datatype in CDA, recognizing that it might not be total cool.
2. Set the II as being not fully specified (and so requiring use of nullFlavor), perhaps committing the URL to another attribute so that the receiver might have some chance of fixing it on their end.
3. Giving up completely

Option 3 is not an option I like, so I discarded it.  You can do what you want, I almost never give up.
Option 2 is what I decided to use for my purposes.  It works, is technically valid, and might cause some complaints, but I can say, well, that URL is NOT KNOWN to my system, so we produce something technically correct with all the info the receiver might use to fix it.  So for:
    <system value=''/>
    <value value='my example id'/>

I would use something like:
  <id nullFlavor='UNK' extension='my example id'
This says, I don't know the full II, I've told you what I know, you deal with it.

But, you could cheat, and say something like: "We know that url#fragment-id means the thing inside url with fragment identifier fragment-id.  So we'll treat it like that.  This is what you would get then:

  <id root='2.16.840.1.113883.4.873
      extension=' example id'/>

I'm not fond of this, because it isn't a totally legitimate answer, although most geeks might understand your reasoning, and what you generated.  It also means that your can no longer trust the content of any id that uses the value of 2.16.840.1.113883.4.873, and they really should be able to.

Fortunately for my uses, the nullFlavor case will only show up in exceptional circumstances.  All the naming systems I use in FHIR have an associated OID mapping.

For what it's worth, the same challenges exist with code system mapping, and I do the same thing: Make sure all my FHIR code systems map to an OID as well.

Wednesday, February 15, 2017

An XSLT Design Pattern (and not just for FHIR to CDA conversions)

I have a couple of XSLT design patterns that I've been using and improving over the past decade, which I pulled out again last night to do some FHIR to CDA transformations.  XSLT isn't what you'd call a strongly object oriented language, nor a strongly typed one.  However, the design patterns I used borrow from experiences I've had with strongly typed, object oriented languages such as Java.

The design pattern is a general one which I've used for a number of strongly typed schema to schema conversions.  FHIR to CDA is just one example.  V2 XML to CDA (or back) is another one, and I've also done this for CDA to ebXML (XDS related work), and at one point for CCR and CDA, even though I'd never really call CCR strongly typed.

The first design pattern is in how I define my transformations.  There are two ways in which you can call a template, and they have different benefits.  Sometimes you want to use one, and sometimes you want to use the other.  When going from one format to another in XML, usually there is a target element that you are trying to create, and one or more source elements you are trying to create it from.

My first method uses apply-templates.
<xsl:apply-templates select='...' mode='target-element-name'/>

You can also call apply-templates with parameters.
<xsl:apply-templates select='...' mode='target-element-name'>
  <xsl:with-param name='some-param' select='some-value'/>

This is pretty straight forward.  I use mode on my transformation templates for a variety of reasons, one of which is that it allows you to build transformation trees that the XSLT engine automates processing with.  More often that not, the name of the mode is the output element I'm targeting to generate.

The second method works more like a traditional function call, using call-template:
<xsl:call-template name='target-element-name'>
  <xsl:with-param name='this' select='the-source-element-to-transform'/>
  <xsl:with-param name='some-param' select='some-value'/>

Now, if the source element is always the same for a given target element (e.g., a FHIR address going to a CDA addr element), you create your actual template signature thus:

<xsl:template name='addr' mode='addr' match='address'>
  <xsl:param name='this' select='.'/>

Note that name and mode are the same.  What you want to create here is an <addr> element in CDA. The input you want to convert is a FHIR address element (I checked several dozen places, just about everywhere the Address datatype is used, it is always called address in FHIR resources).  So that explains the first line.  The name of the template, and its mode, identity what you are trying to create.

The second line is critical, and it has some serious impact on how you write your templates.  Instead of assuming a default context for your transformation, the <xsl:param name='this' select='.'/> sets up a parameter in which you can explicitly pass the transformation context, but which will implicitly use the current context if no such parameter is passed.  When you write your transformation, you have to be careful to use $this consistently, or you'll have some hard to find bugs, because sometimes it might work (e.g., when called using apply-templates), but other times not (e.g., when called using call-template).  It takes some diligence to write templates this way, but after a while you get used to it.

Here's the example for converting a FHIR Address to a CDA addr element.  It's pretty obvious:

<xsl:template name='addr' mode='addr' match='address'>
  <xsl:param name='this' select='.'/>
  <xsl:variable name='use'><xsl:choose>
    <xsl:when test='$this/use/@value="home"'>H</xsl:when>
    <xsl:when test='$this/use/@value="work"'>WP</xsl:when>
    <xsl:when test='$this/use/@value="temp"'>TMP</xsl:when>
    <xsl:if test='$use!=""'>
      <xsl:attribute name='use'><xsl:value-of select='$use'/></xsl:attribute>
    <xsl:for-each select='$this/line'>
      <streetAddressLine><xsl:value-of select='@value'/></streetAddressLine>
    <xsl:for-each select='$this/city'>
      <city><xsl:value-of select='@value'/></city>
    <xsl:for-each select='$this/state'>
      <state><xsl:value-of select='@value'/></state>
    <xsl:for-each select='$this/postalCode'>
      <postalCode><xsl:value-of select='@value'/></postalCode>
    <xsl:for-each select='$this/country'>
      <country><xsl:value-of select='@value'/></country>

[There's a little XSLT shorthand nugget in the above transform, another design pattern I use a lot:
  <xsl:for-each select='x'> ... </xsl:for-each>

 is a much simpler way to say:
  <xsl:if test='count(x) != 0'> ... transform each x ... </xsl:if>

especially when x is a collection of items.]

Now, if you want to drop an address in somewhere, you can do something like this:
  <xsl:apply-templates select='address' mode='addr'/>

Or, you can also do it this way:
  <xsl:call-template name='addr'>
    <xsl:with-param name='this' select='$patient/address'/>

Either works, and in developing large scale transformations, I often find myself using the same template in different ways.  The elegance of this design pattern in XSLT extends further when you have two or more source elements going to the same target element.

In that case, you have two templates with the same mode, but different match criteria.  AND, you have a named template.  Let's presume in the FHIR case, you want to map and Resource.identifier to an id data type (it's not to far-fetched an idea, even if not one I would use). You then write:

  <xsl:template mode='id' match='id'>
  <xsl:template mode='id' match='identifier'>

  <xsl:template name='id'>
    <xsl:param name='this'/>
    <xsl:apply-templates select='$this' mode='id'/>

And the final named template simply uses the match type to automatically select the appropriate template to use based on your input value.

Sometimes you want to create an output element but it isn't always called the same thing, even though it uses the same internal structure.  Using default parameters, you can set this up.  Let's look into example above.  Not EVERY id element is named id.  Sometimes in CDA the have a different name depending on what is being identified.  For example, in the CDA header, you have setId (in fact it's nearly the only case for id).  A more obvious case is code.  Most of the time, code is just code, but sometimes it's ____Code (e.g., priorityCode), but the general structure of a priorityCode (CE CWE [0..1]) is pretty much the same as for code (CD CWE [0..1]).  So, if you were going to convert a FHIR CodableConcept or Coding to a CDA CD/CE data type, you might use the same transformation.

  <xsl:template mode='code' match='code' name='code'>
    <xsl:param name='element' select='"code"'/>
    <xsl:element name='$name'>

You get the idea.  Usually, you want to generate <code>, and so you say nothing.  Sometimes you want to generate something different, and so you add a parameter.
  <xsl:call-template name='code'>
    <xsl:with-param name='this' select='$that/code'/>
    <xsl:with-param name='element' select='"priorityCode"'/>

Remember you can also pass parameters using apply-templates, so this also works:
  <xsl:apply-templates select='$that/code'>
    <xsl:with-param name='element' select='"priorityCode"'/>
Enough chatter, back to work.  HIMSS is only a couple of days away.

   - Keith

P.S.  I've missed being able to post while I've been heads down working towards HIMSS and the Interop showcase.  Hopefully I'll get more time when I get back.

Friday, January 20, 2017

FHIR Product Roadmap Jan 2017 update

This crossed my desk this morning via Grahame Grieve (HL7 Product Manager for FHIR).

   -- Keith

R3 plans
The FHIR project is presently finalising "STU3" (Standard for Trial Use, release 3). This 3rd major milestone is currently close to completion. We've been meeting in San Antonio this week to finalise ballot reconciliation, perform testing and quality activities, and we are now focusing on preparing the final publication package. Following our publication plan we expect to be publishing release 3 on or about Mar 20.
R4 plans
Once R3 is published, we will start working on release 4. The various committees that manage the different parts of Release 4 have been discussing their scope of work for R4, and planning their engagement and implementation activities to support that this week.
Some of the major things under consideration for Release 4:
<![if !supportLists]>·         <![endif]>Improvements across all domains
<![if !supportLists]>·         <![endif]>Cds-hooks integrated in FHIR Specification
<![if !supportLists]>·         <![endif]>Query language framework
<![if !supportLists]>·         <![endif]>Support for integrating research and clinical practice
The most significant change is that R4 is expected to be the first 'normative version'. It's important to understand what that means. We will continue to follow our overall maturity model, where content gradually matures through testing and implementation activities that demonstrate success in the real world. The end of the process is "normative" ("FMM level 6"), where the standard becomes stable, and breaking changes are no longer considered.
Only some portions of the specification are candidates for being normative. We are currently considering balloting the following parts of the specification as normative:
<![if !supportLists]>·         <![endif]>Infrastructure (API, data types, XML/JSON formats, conformance layer resources like StructureDefinition and ValueSet)
<![if !supportLists]>·         <![endif]>Administration (amongst others Patient, Organization, Practitioner)
We will continue to seek and receive comments about this. Some clinical resources may be considered, depending how implementation experience unfolds this year.
Overall planned R4 timeline:
<![if !supportLists]>·         <![endif]>Dec 2017: publish first draft of R4 for comment (finalise plans for normative sections)
<![if !supportLists]>·         <![endif]>Jan 2018: first R4 based connectathon(s)
<![if !supportLists]>·         <![endif]>April 2018: ballot R4
<![if !supportLists]>·         <![endif]>May – Sept 2018: ballot reconciliation
<![if !supportLists]>·         <![endif]>Oct 2018: publish FHIR R4
We will conduct a round of market consultations in Aug/Sept 2017 to seek comment on this timeline from the FHIR community.
Note that this timelines anticipates that we publish R4 in October irrespective of the outcome of the normative ballot. Anything that has not passed normative ballot will continue to published as STU. We are still working on preparation, quality and balloting processes to support the normative FHIR ballot.
Longer term, we anticipate following R4 with a roughly 18 month publication cycle, with increasing normative content.
Implementation Progress
FHIR is a specification for a common API for exchanging healthcare data between information systems. Any information system supporting the healthcare system can choose to implement the common API, and exchange data following the rules. FHIR enables a 'healthcare web' to exist, but doesn't actually create it.
HL7 is pleased to work on the FHIR specification with many hundreds of partners, who are all implementing the specification to exchange data in service of the healthcare needs to their enterprises, their customers, and, ultimately, patients. HL7 does not 'implement' the specification (other than various prototype/test services) – our partners and other healthcare services do.
Argonaut Project
One particularly important sub-group of the FHIR community is the Argonaut project, which is a joint project of major US EHR vendors to advance industry adoption of FHIR and we've had many questions about the Argonaut implementation timeline for EHR access. With regard to the Argonaut community:
<![if !supportLists]>·         <![endif]>The Argonaut STU2 specification for Common Clinical Data Set elements is close to being finalized and will be announced shortly.  The Argonaut STU3 specification for Provider Directory will be published after final balloting of STU3
<![if !supportLists]>·         <![endif]>Most Argonaut members who are certifying an API with ONC are using the Argonaut specification; most certifications are expected in Q1/Q2 2017
<![if !supportLists]>·         <![endif]>Software roll-outs have commenced — progress will vary depending on the vendor
<![if !supportLists]>·         <![endif]>It is presently unknown what the adoption rate by provider institutions will be — MU and MACRA in the US provide incentives to make a patient-facing API available by the end of 2017
<![if !supportLists]>·         <![endif]>Some of the Argonaut interfaces provide additional functionality not yet described in the Argonaut specification, but there is considerable appetite for additional services beyond what is currently available. The Argonaut project will be making announcements about its future plans shortly which will be announced in a press release, through collaboration channels, and at